TypeScript 之 JavaScript文件类型检查

news2024/9/20 20:30:57

启用对 JavaScript 文件的类型检查

在 TypeScript 编译选项 compilerOptions 全部配置项 中,可以通过以下2个属性配置 JavaScript Support:

  • allowJs

    • 是否允许编译 JavaScript 文件。
    • 默认值是 false。在默认情况下,TypeScript 编译器只处理 .ts.tsx.d.ts文件,不会编译 .js文件。
  • checkJs

    • 是否对 JavaScript 文件进行类型检查。
    • 默认值是 false。在默认情况下,TypeScript 编译器不会对 JavaScript 文件进行类型检查。

tsconfig.json 中配置:

{
  "compilerOptions": {
    "allowJs": true,
    "checkJs": true,
    "target": "es5",
    "module": "commonjs",
    "strict": true
  }
}

类型检查的范围和限制

  1. 类型推断:TypeScript 会尝试对 JavaScript 文件中的变量和函数进行类型推断。例如,如果一个变量被赋值为一个字符串,TypeScript 会推断该变量的类型为字符串。注意:由于 JavaScript 是动态类型语言,类型推断可能不是完全准确的。
  2. 函数参数和返回值:对于有明确参数和返回值类型注释的 JavaScript 函数,TypeScript 可以进行更严格的类型检查。如果函数的实际参数类型与注释不匹配,或者返回值类型与预期不符,TypeScript 会报告错误。
  3. 模块导入和导出:当 JavaScript 文件使用模块导入和导出时,TypeScript 可以检查导入和导出的类型是否匹配。但是,如果导入的模块没有类型声明文件(.d.ts),类型检查可能会受到限制。

添加注释忽略类型检查

使用 // @ts-nocheck 忽略类型检查

// @ts-nocheck 注释可以用来忽略对特定 JavaScript 文件的类型检查。

如果"allowJs": true,"checkJs": true,,需要对某个JavaScript文件关闭类型检查,可以在文件的顶部添加 // @ts-nocheck 注释:

// @ts-nocheck
function add(a, b) {
  return a + b;
}

const result = add("Hello", 5);
console.log(result);

这样,TypeScript 在处理这个文件时将忽略类型检查,不会报告错误。

使用 // @ts-check 开启类型检查

如果"allowJs": true,"checkJs": false,,但是要对某个JavaScript文件进行类型检查,可以添加 // @ts-check 注释:

// @ts-check
function multiply(a, b) {
  return a * b;
}

const product = multiply(3, "four");
console.log(product);

当 TypeScript 处理这个文件时,会报告类型错误。

使用 // @ts-ignore 忽略特定行的错误

如果"allowJs": true,"checkJs": true,,需要让 TypeScript 忽略JavaScript文件某一行的类型检查错误,可以该语句上方添加// @ts-ignore 注释:

let a = 10;  // ts 类型检查 推断 a 是number

a = 'hello world'; // 报错:不能将类型“string”分配给类型“number”。

// @ts-ignore
a = 'hello world';  // 类型检查错误被忽略,不会报错

// @ts-ignore 仅仅对紧随其后的那一行代码做约束,可以写在代码的任意位置

使用// @ts-expect-error忽略特定行的错误

如果"allowJs": true,"checkJs": true,,需要让 TypeScript 忽略JavaScript文件某一行的类型检查错误,可以该语句上方添加// @ts-expect-error注释:

let a = 10;  // ts 类型检查 推断 a 是number

a = 'hello world'; // 报错:不能将类型“string”分配给类型“number”。

// `// @ts-expect-error`
a = 'hello world';  // 类型检查错误被忽略,不会报错

// @ts-expect-error// @ts-ignore 的区别:
如果随后一行代码是没有类型错误,代码提示器就会认为@ts-expect-error 没有被使用。 @ts-ignore不会有提示。
在这里插入图片描述

JavaScript 用 JSDoc 来 明确类型信息

.js文件里,类型可以和在.ts文件里一样被推断出来。如同TypeScript,--noImplicitAny会在编译器无法推断类型的位置报错。

所有JSDoc支持的模式,请看JSDoc中文文档。

使用JSDoc来明确类型信息:

  • 使用 @param 标签来指定函数参数的类型
  • 使用 @return 标签来指定函数的返回值类型。

示例:

/**
 * @param {number} num1 - The first number.
 * @param {number} num2 - The second number.
 * @return {number} - The sum of the two numbers.
 */
function sum(num1, num2) {
  return num1 + num2;
}
// 使用示例
console.log(sum( 'hello', 10 )); // 报错:类型“string”的参数不能赋给类型“number”的参数。

在这个例子中,使用 @param {number} num1@param {number} num2 来指定函数 sum 的两个参数都是数字类型。
sum( 'hello', 10 ) 会报错:类型“string”的参数不能赋给类型“number”的参数。
在这里插入图片描述

TS支持的JSDoc

下面的列表列出了当前所支持的JSDoc注解,你可以用它们在JavaScript文件里添加类型信息。

注意,没有在下面列出的标记(例如@async)都是还不支持的。

  • @type
  • @param (or @arg or @argument)
  • @returns (or @return)
  • @typedef
  • @callback
  • @template
  • @class (or @constructor)
  • @this
  • @extends (or @augments)
  • @enum

@type

可以使用@type标记并引用一个类型名称(原始类型,TypeScript里声明的类型,或在JSDoc里@typedef标记指定的) 可以使用任何TypeScript类型和大多数JSDoc类型。

语法:

@type {type} - description

示例:

/**
/**
 * @type {Object} person
 * @property {string} name - The person's name.
 * @property {number} age - The person's age.
 */

let person = {
  name: 'John',
  age: 36,
  address: 'xxxxx'
}

变量person 有两个明确的属性,name 是字符串类型,用于表示人的名字;age 是数字类型,用于表示人的年龄。但是又不止这两个属性,没有明确定义的属性address 也不会报错。


指定对象字面量类型(使用 {} 来表示对象类型,并列出对象的属性和类型):

/** @type {{name: string, age: number}} */
let person = { name: 'John', age: 30 };
person = { name: 'John', age: 30, address: 'xxxxx' }; // 报错

在这里插入图片描述

有多种方式来指定数组,其中 type 是数组元素的类型:

  • @type Array<type>
  • @type Array.<type>
  • @type {type[]}

示例:

/** @type {Array<number>} */
let arr = [1, 2, 3];
arr.push('abc'); // 报错:类型“string”的参数不能赋给类型“number”的参数。

@type {Array<number>} 指定数组的每项元素的类型是number


使用 | 来表示联合类型:

/** @type {Array<number | string>} */
let arr = [1, 2, 3];
arr.push('abc');

现在,数组的每项元素的类型是 numberstring

在类型后面加上 ? 表示该类型是可选的:

/** @type {{name: string, age?: number}} */
let person = { name: 'John' };
person.age = 36;

可以使用字符串和数字索引签名来指定map-likearray-like的对象,使用标准的JSDoc语法或者TypeScript语法:

/**
 * A map-like object that maps arbitrary `string` properties to `number`s.
 *
 * @type {Object.<string, number>}
 */
let stringToNumber;

/** @type {Object.<number, object>} */
let arrayLike;

这两个类型与TypeScript里的{ [x: string]: number }{ [x: number]: any }是等同的。编译器能识别出这两种语法。

分析示例:

  • 第一个类型注释
    • “A map-like object that maps arbitrary string properties to numbers.”这个描述清晰地说明了这个对象的预期用途,即它是一个类似映射(map)的对象,将任意的字符串属性映射到数字。
    • @type {Object.<string, number>}表示这个变量 stringToNumber 被期望是一个对象,其键为字符串类型,值为数字类型。

使用示例:

/**
 * A map-like object that maps arbitrary `string` properties to `number`s.
 *
 * @type {Object.<string, number>}
 */
let stringToNumber = {
  key1: 10,
  key2: 20
};
  • 第二个类型注释
    • @type {Object.<number, object>}表明变量 arrayLike 被期望是一个对象,其键为数字类型,值为任意对象类型。

这种类型注释可以用于表示一个类似数组的对象,其中数字键可以用来模拟数组的索引,而值可以是各种不同类型的对象。

使用示例:

/** @type {Object.<number, object>} */
let arrayLike = {
  0: { name: 'obj1' },
  1: { name: 'obj2' }
};


指定一个对象是 Window ,该对象应该具有 Window 对象的属性和方法:

/** @type {Window} */
let win = window;

win.alert('Hello!');


指定一个变量 是一个类似于 Promise 的对象,并且这个 Promise 最终会 resolve 为一个字符串值:

/** @type {PromiseLike<string>} */
let promisedString;

在这个示例中:

  • Promise 类似对象:
    • 在 JavaScript 中,Promise 是一种用于处理异步操作的机制。它代表了一个尚未完成但预期在未来完成的操作,并提供了一种方式来处理操作成功(resolved)或失败(rejected)的情况。
    • PromiseLike 表示具有与 Promise 类似的行为的对象。它不一定完全符合 Promise 的规范,但可能具有 .then().catch() 等方法,用于处理异步操作的结果。
      注意:PromiseLike<string> 期望的 .then() 方法应该接受两个可选的回调函数,一个用于处理成功的情况,一个用于处理失败的情况。
  • 字符串结果:
    • @type {PromiseLike<string>}指定了这个 Promise 类似对象最终会产生一个字符串类型的结果。当这个异步操作完成时,可以预期从这个对象中获取一个字符串值。

指定变量是一个HTMLElement 类型的对象:

/** @type {HTMLElement} */
let myElement = document.querySelector(selector);
element.dataset.myData = '';

在这个示例中:
@type {HTMLElement}表明变量 myElement 被期望是一个 HTMLElement 类型的对象。在 JavaScript 中,HTMLElement 代表 HTML 文档中的一个元素。


使用TypeScript或Closure语法指定函数类型:

/** @type {function(string, boolean): number} Closure syntax */
let sbn;
/** @type {(s: string, b: boolean) => number} Typescript syntax */
let sbn2;

在这个示例中:

  • JSDoc 类型注释(Closure 语法)
    • @type {function(string, boolean): number}
      这个 JSDoc 类型注释表明变量 sbn 被期望是一个函数类型。这个函数接受两个参数,第一个参数是字符串类型(string),第二个参数是布尔类型(boolean),并且这个函数返回一个数字类型(number)的值。
  • TypeScript 类型注释语法
    • @type {(s: string, b: boolean) => number}
      这是使用 TypeScript 类型注释语法来指定变量 sbn2 的类型。同样,它表示 sbn2 是一个函数,接受一个字符串参数 s 和一个布尔参数 b,并返回一个数字。

用法示例:

/** @type {function(string, boolean): number} Closure syntax */
let sbn = function (str, bool) {
  // 根据字符串和布尔值进行一些操作并返回一个数字
  if (bool) {
    return str.length;
  } else {
    return 0;
  }
};

/** @type {(s: string, b: boolean) => number} Typescript syntax */
let sbn2 = function (s, b) {
  return b ? s.length : -1;
};

console.log(sbn('Hello', true));  // 5
console.log(sbn2('World', false)); // -1

直接使用未指定的Function类型:

/** @type {Function} */
let fnOne;
/** @type {function} */
let fnTwo;

在 JavaScript 中,Function (or function)是所有函数的类型。使用这个注释意味着 fnOnefnTwo可以被赋值为任何函数。


Closure的其它类型也可以使用:

/**
 * @type {*} - can be 'any' type
 */
let star;
/**
 * @type {?} - unknown type (same as 'any')
 */
let question;

类型注释说明:

  • @type {*} :
    这个 JSDoc 类型注释表明变量 star 可以是任何类型。在一些情况下,使用 * 表示“any”类型是为了在文档中明确指出该变量的类型是不确定的或者可以是任意类型。
  • @type {?}
    这个 JSDoc 类型注释表明变量 question 的类型是未知的,并且说它与“any”类型相同。

转换

在括号表达式前面使用@type标记,可以将一种类型转换成另一种类型:

/**
 * @type {number | string}
 */
 
 // 根据随机数的结果,将变量 numberOrString 赋值为字符串 "hello" 或者数字 100。
let numberOrString = Math.random() < 0.5 ? "hello" : 100;

// 类型断言:将 numberOrString 断言为数字类型,并赋值给 typeAssertedNumber。
let typeAssertedNumber = /** @type {number} */ (numberOrString)

导入类型

可以使用导入类型从其它文件中导入声明。 这个语法是TypeScript特有的,与JSDoc标准不同:

/**
 * @param p { import("./a").Pet }
 */
function walk(p) {
  console.log(`Walking ${p.name}...`);
}
  • @param p { import("./a").Pet }
    这个 JSDoc 类型注释表明函数 walk 的参数 p 是从模块 ./a 中导入的类型为 Pet 的对象。这指定了参数 p 的预期类型。

如果模块 ./a 定义了 Pet 类型如下:

// 模块./a
export class Pet {
  constructor(name) {
    this.name = name;
  }
}

可以这样使用 walk 函数:

import { Pet } from './a';
const myPet = new Pet('Fluffy');
walk(myPet);

导入类型也可以使用在类型别名声明中:

/**
 * @typedef Pet { import("./a").Pet }
 */

/**
 * @type {Pet}
 */
let myPet; // myPet 的类型 是 Pet 的类型别名。
myPet.name;
  • @typedef Pet { import("./a").Pet }:
    这里使用 @typedef 定义了一个名为 Pet 的类型别名。它表示这个新定义的 Pet 实际上是从模块 ./a 中导入的类型。
  • @type {Pet}
    这个类型注释表明变量 myPet 的类型是前面定义的 Pet 类型别名,也就是从模块 ./a 中导入的那个类型。

导入类型可以用在从模块中得到一个值的类型:

/**
 * @type {typeof import("./a").x }
 */
let x = require("./a").x;
  • @type {typeof import("./a").x }
    这个 JSDoc 类型注释表明变量 x 的类型是模块 ./a 中导出的变量 x 的类型。具体来说,typeof import("./a").x 获取了模块 ./ax 的类型信息,这里使用这个类型信息来注释变量 x,表示变量 x 应该与模块 ./a 中的 x 具有相同的类型。
  • let x = require("./a").x:
    这行代码使用 CommonJS 模块规范的 require 函数导入模块 ./a,并将模块中导出的 x 赋值给变量 x

@typedef

在 JSDoc 中,@typedef 用于定义一个类型别名。

语法:

@typedef {type} name - description

其中,type 是现有的类型,name 是新定义的类型别名,description 是对这个类型别名的描述。

示例:

/**
 * @typedef {Object} Person
 * @property {string} name - The person's name.
 * @property {number} age - The person's age.
 */

/**
 * @param {Person} person - A person object.
 */
function greet(person) {
  console.log(`Hello, ${person.name}! You are ${person.age} years old.`);
}

const person1 = { name: 'John', age: 30 };
greet(person1);

在这个例子中,@typedef 定义了一个名为 Person 的类型别名,它是一个对象类型,包含 name(字符串类型)和 age(数字类型)两个属性。然后,函数 greet 接受一个参数 person,其类型被注释为 Person,表示这个参数应该是一个符合 Person 类型定义的对象。

@type@typedef 的区别

  • @type
    • 用于指定一个变量、参数或返回值的具体类型。它通常用于为已有的类型提供类型注释,而不是创建新的类型别名。
  • @typedef
    • 用于定义一个新的类型别名。它允许你为一个复杂的类型结构创建一个更具描述性的名称,以便在代码中重复使用。

@param@returns

在 JSDoc 中,@param用于描述函数的参数。
@param语法:

@param {type} name - description

其中 type 是参数的类型,name 是参数的名称,description 是对参数的描述。

注意:@param语法和@type相同,但增加了一个参数名。 使用[]可以把参数声明为可选的。


在 JSDoc 中,@returns用于描述函数的返回值。
@returns语法:

@returns {type} - description

其中 type 是函数的返回值类型,description 是对返回值的描述。

示例:

/**
 * @param {number} a - The first number.
 * @param {number} b - The second number.
 * @param {number=} c - The third number.
 * @param {number} [d=10] - The fourth number.
 * @returns {number} 
 */
function sum(a, b, c, d = 10) {
  c = c ?? 0;
  return a + b + c + d;
}

console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, undefined, undefined)); // 3
console.log(sum(1, 2, undefined, 10)); // 13

参数cd被标记为可选参数。在调用函数时它们可能没有被传入值。因此,需要对参数进行类型判断。

@typedef@param

@typedef可以声明复杂类型。它和@param在语法上有一定的相似性,但用途不同。

使用@typedef 定义一个包含多个属性的对象类型别名:

/**
 * @typedef {Object} Person
 * @property {string} name - The person's name.
 * @property {number} age - The person's age.
 * @property {string[]} hobbies - The person's hobbies.
 */

/**
 * @param {Person} person - A person object.
 */
function displayPersonInfo(person) {
  console.log(`Name: ${person.name}, Age: ${person.age}, Hobbies: ${person.hobbies.join(', ')}`);
}

@param允许使用相似的语法。 注意,嵌套的属性名必须使用参数名做为前缀:

/**
 * @param {Object} options - The shape is the same as SpecialType above
 * @param {string} options.prop1
 * @param {number} options.prop2
 * @param {number=} options.prop3
 * @param {number} [options.prop4]
 * @param {number} [options.prop5=42]
 */
function special(options) {
  let op5 = options.prop5 ?? 0;
  return (options.prop4 || 1001) + op5;
}

使用@typedef声明函数类型的别名:

/**
 * @typedef {(a: number, b: number) => number} MathOperation
 */

/**
 * @param {MathOperation} operation - A math operation function.
 * @param {number} x - The first number.
 * @param {number} y - The second number.
 */
function performMathOperation(operation, x, y) {
  return operation(x, y);
}

在这个例子中,定义了一个名为MathOperation的函数类型别名,代表接受两个数字参数并返回一个数字的函数类型。在函数performMathOperation中使用了MathOperation来注释参数operation

@param {MathOperation} operation - A math operation function.:这个参数注释表明参数 operation 的类型是前面定义的 MathOperation,即一个特定的函数类型。这意味着在调用这个函数时,传入的 operation 参数应该是一个接受两个数字参数并返回一个数字的函数。

@callback

在 JSDoc 中,@callback用于定义回调函数的类型。

语法:

@callback callbackName - description

其中,callbackName是回调函数的名称,用于在文档中引用这个回调函数类型。description是对回调函数的描述。
@callback的注释块内部,可以使用@param@returns等标签来描述回调函数的参数和返回值类型。

示例:

/**
 * @callback ProcessFunction
 * @param {string} data - The input data.
 * @returns {number} The processed result.
 */

/**
 * Processes data using a callback function.
 * @param {string} inputData - The data to process.
 * @param {ProcessFunction} callback - The callback function to process the data.
 */
function processData(inputData, callback) {
  const result = callback(inputData);
  return result;
}

在这个例子中:

  1. 使用@callback定义了一个名为ProcessFunction的回调函数类型,它接受一个字符串类型的参数data,并返回一个数字类型的值。
  2. 在函数processData的文档注释中,使用这个回调函数类型来注释参数callback,表示这个参数应该是一个符合ProcessFunction类型定义的回调函数。

@template

在 JSDoc 中,@template用于描述函数或类的模板参数。

语法:

@template {typeParam} name - description

其中,typeParam是模板参数的类型,name是模板参数的名称,description是对模板参数的描述。

使用@template声明泛型:

/**
 * @template T
 * @param {T} x - A generic parameter that flows through to the return type
 * @return {T}
 */
function someArg(x){ return x }

console.log(someArg(5)); // 5
console.log(someArg('hi')); // 'hi'
const obj = { name: "John", age: 30 };
console.log(someArg(obj)); // { name: "John", age: 30 }

使用 @template 声明了一个模板参数 T
@param {T} x表明函数接受一个参数 x,其类型为模板参数 T
@return {T}明确了函数的返回值类型也是模板参数 T
函数换入的参数类型与返回值的类型保持一致。

用逗号或多个标记来声明多个类型参数:

/**
 * @template T,U,V
 * @template W,X
 */

可以在参数名前指定类型约束。
例如,对第一个参数的类型进行严格的限制:

/**
 * @template {string} K - K must be a string or string literal
 * @template {{ serious(): string }} Seriousalizable - must have a serious method
 * @param {K} key
 * @param {Seriousalizable} object
 */
function seriousalize(key, object) {
  // ????
}

@template {string} K定义了一个模板参数 K,并限制其类型为字符串或字符串字面量。
也就是说,在调用函数seriousalize时,第一个参数 key 的类型必须是字符串或字符串字面量。

一个综合示例:

/**
 * @template T
 * @function mapArray
 * @param {T[]} array - The input array.
 * @param {(item: T) => T} callback - The callback function to apply to each item.
 * @returns {T[]} The mapped array.
 */

function mapArray(array, callback) {
  return array.map(callback);
}

const numbers = [1, 2, 3];
const doubledNumbers = mapArray(numbers, (num) => num * 2);
console.log(doubledNumbers); // [2, 4, 6]

const strings = ['a', 'b', 'c'];
const upperCaseStrings = mapArray(strings, (str) => str.toUpperCase());
console.log(upperCaseStrings); // ['A', 'B', 'C']

在这个例子中,@template T定义了一个模板参数T,表示函数mapArray可以接受任何类型的数组,并对数组中的每个元素应用一个回调函数。函数mapArray的参数array被注释为T[],表示一个类型为T的数组,参数callback被注释为(item: T) => T,表示一个接受类型为T的参数并返回类型为T的函数。

@class (or @constructor)

在 JSDoc 中,@constructor用于标记一个函数为构造函数。

语法:

@constructor通常放在函数的文档注释中,紧跟在函数的描述之后。

示例:

/**
 * A simple class representing a person.
 * @constructor
 * @param {string} name - The person's name.
 * @param {number} age - The person's age.
 */
function Person(name, age) {
  this.name = name;
  this.age = age;
}

const person1 = new Person('John', 30);
console.log(person1.name);
console.log(person1.age);

在这个例子中,@constructor标记了函数Person为构造函数。当使用new关键字调用Person函数时,它会创建一个新的对象,并将传入的参数赋值给对象的属性。

使用@constructor,可以明确一个函数是用于创建对象的构造函数。
不幸的是,这意味着那些既能构造也能直接调用的构造函数不能使用@constructor

@this

编译器通常可以通过上下文来推断出this的类型。
在 JSDoc 中,@this用于描述函数中 this 的类型。

语法:

@this {type} - description

其中,typethis 的类型,description是对 this 的描述。

明确this指向“上下文对象”:

/**
 * @this {Object} context - The context object.
 * @param {number} a - The first number.
 * @param {number} b - The second number.
 * @returns {number} The sum of the two numbers.
 */
function sum(a, b) {
  return this.a + this.b;
}

const context = { a: 5, b: 3 };
const result = sum.call(context, context.a, context.b);
console.log(result); // 8

在这个例子中,@this {Object} context - The context object.表示在函数 sum 中,this 的类型是一个对象,描述为“上下文对象”。通过 sum.call(context, context.a, context.b) 调用函数 sum ,并将 context 作为 this 的值传入,从而可以在函数内部使用 this.athis.b 来访问 context 对象的属性。

明确this指向HTML 元素对象:

/**
 * @this {HTMLElement}
 * @param {*} e
 */
function callbackForLater(e) {
  this.style.height = parseInt(e) + 'px';
}

@this {HTMLElement}
这个注释表明在函数 callbackForLater 中,this 的类型被期望为 HTMLElement。当这个函数被调用时,this 应该指向一个 HTML 元素对象。

@extends (or @augments)

在 JSDoc 中,@extends用于表示一个类型继承自另一个类型。

语法:

@extends {type} - description

其中,type是被继承的类型,description是对继承关系的描述。

当JavaScript类继承了一个基类,无处指定类型参数的类型。而@extends标记提供了这样一种方式:

/**
 * @template T
 * @extends {Set<T>}
 */
class SortableSet extends Set {
  // ...
}

注意@extends只作用于类。当前,无法实现构造函数继承类的情况。

@enum

在 JSDoc 中,@enum用于定义枚举类型。

语法:

@enum {Object} name - description

其中,name是枚举的名称,description是对枚举的描述。在注释块内部,可以使用键值对的形式来定义枚举的成员。

@enum标记允许创建一个对象字面量,它的成员都有确定的类型。与JavaScript里大多数的对象字面量不同:它不允许添加额外成员。

/** @enum {number} */
const JSDocState = {
  BeginningOfLine: 0,
  SawAsterisk: 1,
  SavingComments: 2,
}

注意JSDoc 的@enum与TypeScript的@enum大不相同,JSDoc 的@enum可以是任何类型。这意味着可以根据需要定义枚举成员的值为数字、字符串或其他复杂的数据类型。

例如,可以定义一个枚举,其中成员的值是对象或函数:

/**
 * @enum {Object} MyEnum
 * @property {function(): void} Action1 - Description of Action1.
 * @property {function(): void} Action2 - Description of Action2.
 */

不支持的写法

对象字面量中标记属性可选是不能使用=后缀的:

// 错误示例
const obj = {
  prop1: 'value1',
  prop2: 'value2',
  prop3=: 'value3' // 错误的语法,不能用 =: 来表示可选属性
};

// 正确的写法是使用 ? 表示可选属性
const obj = {
  prop1: 'value1',
  prop2: 'value2',
  prop3?: 'value3' // 正确的语法,表示 prop3 是可选属性
};

Nullable类型只在启用了strictNullChecks检查时才起作用:

/**
 * @type {?number}
 * With strictNullChecks: true -- number | null
 * With strictNullChecks: off  -- number
 */
var nullable;

@type {?number}描述变量 nullable 的类型可以是number或者 null


Non-nullable类型没有意义,以其原类型对待:

/**
 * @type {!number}
 * Just has type number
 */
var normal;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2042689.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

从0开始搭建vue + flask 旅游景点数据分析系统(十二)【完结篇】:用户管理之增删改查、用户信息更新

这一期继续完成用户管理的增删改查和登录用户修改自己信息的功能&#xff0c;首先完成后端接口的功能。 1 后端接口 这边有查询列表接口、查询单个接口、新增接口、修改接口、删除接口这5个接口&#xff1a; #** 用户信息的增删改查 *** # 用户列表 main.route(/users, meth…

离线安装prometheus与Grafana实现可视化监控

简介 prometheus 是一个专为云环境设计的开源系统监控和警报工具&#xff0c;它收集并存储多维度的时间序列数据&#xff0c;通过PromQL查询语言提供强大的数据检索能力&#xff0c;并支持可视化及警报功能。而 Grafana 则是一个开源的数据可视化平台&#xff0c;能够与包括Pr…

2024软件测试面试官在面试的时候会做些什么?

虽然没有了金九银十&#xff0c;但是公司的测试HC还是有完全锁死&#xff0c;断断续续的也在帮着面试一些人。同时星球上也有很多人在关注面试的问题&#xff0c;本文就以自己的经验&#xff0c;从面试官的角度&#xff0c;聊聊面试过程中的那些事。 一、笔试面试官 在面试开…

使用Flv.js无法播放视频

背景 由于项目需要&#xff0c;搭建了一套SRS直播服务&#xff0c;通过直播录制将视频报错并在本地播放。视频存储的格式为flv&#xff0c;所以使用flv.js插件来播放。测试时发现录制的视频无法播放&#xff0c;经过排查找到原因。 报错信息 控制台并无明显报错&#xff0c;…

Keepalived高可用集群--几个实验带你认识集群的坚实后盾

一、KeepAlived的发展 Keepalived起初是为LVS设计的&#xff0c;专门用来监控集群系统中各个服务节点的状态&#xff0c;它根据TCP/IP参考模型的第三、第四层、第五层交换机制检测每个服务节点的状态&#xff0c;如果某个服务器节点出现异常&#xff0c;或者工作出现故障&#…

神经串联式语音转换:对基于串联的单次语音转换方法的再思考 论文笔记

NEURAL CONCATENATIVE SINGING VOICE CONVERSION: RETHINKING CONCATENATION-BASED APPROACH FOR ONE-SHOT SINGING VOICE CONVERSION 笔记 发现问题&#xff1a; 在any-to-any的转换中,由于内容和说话人音色的解耦不足,导致源说话人的音色部分仍保留在转换后的音频中&#x…

Dom4j详细介绍

Dom4j 1.1 解析概览 将数据存储为XML格式后&#xff0c;程序化地访问这些数据变得至关重要。虽然Java基础的IO操作能够实现这一目标&#xff0c;但这一过程往往既复杂又繁琐&#xff0c;尤其是在处理大型文件或需要频繁读写操作的场景下。为了解决这些问题&#xff0c;开发者…

多条折线图修改图例以及自定义tooltip

在图例后面添加所有数据之和修改之后 series 中的name之后导致tooltip也加上了重新自定义tooltip&#xff0c;去掉总量统计 核心代码 监听数据改变计算总量修改name字段自定义 tooltip // 计算每条线的总和 const sum1 this.VALUE1.reduce((acc, val) > acc val, 0); co…

【python】在Python中读取和加解密PDF文件的详细教程与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Python酷库之旅-第三方库Pandas(082)

目录 一、用法精讲 341、pandas.Series.str.startswith方法 341-1、语法 341-2、参数 341-3、功能 341-4、返回值 341-5、说明 341-6、用法 341-6-1、数据准备 341-6-2、代码示例 341-6-3、结果输出 342、pandas.Series.str.strip方法 342-1、语法 342-2、参数 …

go语言源码解读之数据结构堆

概述 堆(heap)&#xff0c;是一种计算中常用的数据结构。本文我们将探讨对的特性、实现细节以及实际应用场景。 基本概念 堆是一种特殊的完全二叉树。堆分为大顶堆与小顶堆。 大顶堆的特点是&#xff0c;父节点的值总是大于或等于其子节点的值。 小顶堆的特点是&#xff0c…

SocialFi新纪元:Match革新金融与社交的融合艺术

前言 Match在SocialFi领域的创新探索&#xff0c;或将金融与社交的融合艺术推向新的高度&#xff01; SocialFi自带"爆点”属性&#xff0c;Web 3.0巨型流量池 统计数据显示&#xff0c;2023年第三季度&#xff0c;全球约有54亿人活跃在互联网上&#xff0c;而社交媒体领…

江协科技STM32学习笔记(第13章 WDG看门狗)

第13章 WDG看门狗 13.1 WDG看门狗 13.1.1 WDG简介 看门狗就是程序运行的一个保障措施&#xff0c;我们得在程序中定期地喂狗&#xff0c;如果程序卡死了&#xff0c;没有在规定的时间里喂狗&#xff0c;那么看门狗硬件电路就会自动帮我们复位一下&#xff0c;防止程序长时间…

<keep-alive> 一分钟了解

<keep-alive> 一分钟了解 <keep-alive> 是 Vue.js 提供的一个抽象组件&#xff0c;它的主要用途是在页面或组件切换时保留其状态&#xff0c;避免重复执行昂贵的渲染操作&#xff0c;从而提升应用性能。 文章目录 <keep-alive> 一分钟了解 一、 <keep-ali…

Ubuntu如何实现每天定时关机

要在Ubuntu中实现每天定时关机&#xff0c;你可以使用cron来安排定时任务。以下是具体的步骤&#xff1a; 步骤 1: 创建脚本 打开终端。使用文本编辑器创建一个新的文件。例如&#xff1a; nano ~/shutdown_script.sh 步骤 2: 编写脚本 在编辑器中输入以下内容&#xff1a…

华府便利店信息管理系统

TOC springboot239华府便利店信息管理系统 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&#xff0c;规…

花四小时,写了个在线实时绘制等值面图小软件,明晚上线,喜欢的小伙伴关注哦

科研党的福音&#xff0c;绘图再也不需要安装一堆软件了&#xff0c;可以在线绘图了&#xff1b; 只需要传入绘制的区间、色值、以及所需要绘制的数据就可以直接出图了&#xff0c;可绘制各种等值面图&#xff0c;比如降水分布&#xff0c;高温分布&#xff0c;人口分布&#x…

文心快码真的很好用!!!

最近被身边的好友安利到了一个百度的新产品文心快码&#xff08;comate&#xff09;&#xff0c;没想到体验下来真的很好用&#xff0c;非常容易上手&#xff0c;解放了我的双手&#xff0c;提高了代码生产力&#xff01;可能有很多小伙伴不知道怎么使用comate,而我作为这类工具…

C语言-将n个数输入时顺序的逆序排列,用指针函数实现

一、题目要求&#xff1a; 将n个数输入时顺序的逆序排列&#xff0c;用指针函数实现 二、程序: #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main() {int n;printf("请输入一共有多少数:\n");scanf("%d", &n);int arr[100], i;…

大模型之二十五-人工智能新纪元

人类社会正式从信息科技时代步入了人工智能时代&#xff0c;相比信息科技革命&#xff0c;人工智能科技革命的影响要深远的多&#xff0c;在这新旧交替剧烈变革期&#xff0c;绝大多数人都有机会。 为了更好的理解人工智能科技革命&#xff0c;首先我们首先梳理一下技术的发展…