您的位置:首页 > 教育 > 锐评 > TypeScript 之 JavaScript文件类型检查

TypeScript 之 JavaScript文件类型检查

2025/2/28 13:52:49 来源:https://blog.csdn.net/fishmemory7sec/article/details/141195728  浏览:    关键词:TypeScript 之 JavaScript文件类型检查

启用对 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 是numbera = '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 是numbera = '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;

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com