当前位置: 首页 > news >正文

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;

相关文章:

TypeScript 之 JavaScript文件类型检查

启用对 JavaScript 文件的类型检查 在 TypeScript 编译选项 compilerOptions 全部配置项 中&#xff0c;可以通过以下2个属性配置 JavaScript Support&#xff1a; allowJs 是否允许编译 JavaScript 文件。默认值是 false。在默认情况下&#xff0c;TypeScript 编译器只处理 .…...

基本数据类型变量间的自动提升与强制转换以及进制的转换

基本数据类型变量间的自动提升与强制转换 测试基本数据类型的运算规则 这里基本类型不包括布尔 运算规则 自动类型提升 当容量小的变量与容量大的变量做运算时&#xff0c;结果自动转换容量大的数据类型 说明&#xff1a;此时容量大小&#xff0c;指的是数据范围大小&…...

SparseConv 的学习笔记

安装 环境设置在74.183 sdfstudio 里面,SparseNeus 推荐的版本是是 torchsparse 2.0.0版本 命令行如下&#xff1a; 需要 C 的 sudo 权限指定安装&#xff1a; ## 安装依赖项 conda install -c conda-forge sparsehash sudo apt-get install libsparsehash-dev 进入官网下…...

vscode 快速生成vue 格式

1.用快捷Ctrl Shift P唤出控制台 输入“Snippets”并选择 Snippets: Configure User Snippets 2.输入vue&#xff0c;选中vue.json vs code自动生成vue.json文件 3.在 vue.json 中添加模板 {"Print to console": {"prefix": "vue2","b…...

react笔记:redux

redux状态管理 安装redux&#xff1a;num i redux 新建redux文件夹&#xff1a; store.jscount_reducer.js count_action.js constant.js (常量&#xff09; 1. store.js文件&#xff1a; // 该文件专门用于暴露一个store对象&#xff0c;整个应用只有一个store对…...

数据结构与算法--图的应用

文章目录 回顾提要连通图生成树最小生成树构造最小生成树的算法普里姆(Prim)算法克鲁斯卡尔(Kruskal)算法 最短路径狄杰斯特拉 (Dijkstra) 算法当前最短路径的更新拓扑排序拓扑排序方法拓扑排序示例总结 回顾 图的遍历方法&#xff1a; 深度优先遍历 (DFS)&#xff1a;从任意…...

【leetcode图文详解】特殊数组II : 空间换时间的“记忆化”,越多越好吗?

题目详解 需求&#xff1a;判断给定区间内的元素是否满足“特殊数组”要求 尝试: 暴力求解? 如果试着直接对每个queries中的区间进行检测而不做其他处理&#xff0c;那么最后不出意外地超时了。。 细想优化策略&#xff0c;不难察觉到其中可能存在大量的重复运算 那还等什…...

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

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

【Python学习-UI界面】PyQt5 小部件7-QSpinBox 计数器

样式如下: 一个 QSpinBox 对象向用户呈现一个文本框&#xff0c;右侧有一个上下按钮&#xff0c;显示一个整数。如果按下上下按钮&#xff0c;文本框中的值将增加/减少。 默认情况下&#xff0c;框中的整数从0开始&#xff0c;最高到99&#xff0c;并以步长1变化。对于浮点数…...

[二次元]个人主页搭建

文章目录 域名买一个免费的 框架HexoHexo-Theme-ParticleX Halo 参考 域名 买一个 有钱人玩这个 免费的 github.io 教程在github官方文档有&#xff1b; 框架 Hexo 静态的 Hexo-Theme-ParticleX Argvchsの小窝 Halo 动态的 halo 参考 基于Hexo框架的GitHub个人主页…...

Spring Data JPA 自动创建时间的相关注解和用法

以Springboot项目为例 在实体类上加上注解 EntityListeners(AuditingEntityListener.class)在相应的字段上添加对应的时间注解 LastModifiedDate 和 CreatedDateApplication启动类中添加注解 EnableJpaAuditing...

Java基础之隐式类型转换

类型转换 基本数据类型表示范围大小排序&#xff1a; 在变量赋值及算术运算的过程中&#xff0c;经常会用到数据类型转换&#xff0c;其分为两类&#xff1a; 隐式类型转换 显式类型转换 1 隐式类型转换 情形1&#xff1a;赋值过程中&#xff0c;小数据类型值或变量可以直…...

【数据结构与算法 | 图篇】Dijkstra算法(单源最短路径算法)

1. 前言 由图&#xff1a; 如果我们想要求得节点1到节点5&#xff08;也可以是其他节点&#xff09;的最短路径&#xff0c;我们可以使用Dijkstra算法。 2. 步骤与思路 1. 将所有顶点标记为未访问(顶点类的visited属性设置为false)。创建一个未访问顶点的集合。 2. 为每个顶…...

windows c转linux c要做的事情。

写在开头&#xff1a; 最近的copy项目要转到windows版本了&#xff0c;一直在跟进做这个事情。 直入主题说下移植过程中可能涉及以下几个方面的调整&#xff1a;‌ 编译器和工具链的更改&#xff1a;‌Windows和Linux使用不同的编译器和工具链&#xff0c;‌因此需要在Windo…...

【高等代数笔记】002.高等代数研究对象(二)

1. 高等代数的研究对象 1.4 一元高次方程的求根 a n x n a n − 1 x n − 1 . . . a 1 x a 0 0 a_{n}x^{n}a_{n-1}x^{n-1}...a_{1}xa_{0}0 an​xnan−1​xn−1...a1​xa0​0 等式左边是一元多项式。 所有一元多项式组成的集合称为一元多项式环。...

ubuntu服务器部署的mysql本地连不上的问题

试过了网上的所有方法,都连不上,可以执行: SELECT user, host, plugin FROM mysql.user WHERE user root; 查一下:plungin这个连接插件是不是auth_socket, auth_socket是只能本地连接的插件,需要修改: ALTER USER root% IDENTIFIED WITH mysql_native_password BY your_pass…...

python redis安装

python redis安装 #方法1、 sudo apt-get install redis-server python 支持包&#xff1a; (其实就一个文件&#xff0c;搞过来就能用) sudo apt-get install python-redis #方法2、 sudo pip install redis...

YJ0043定制版抖音电商卷抢购系统带回收商城抖音电商优惠卷投资理财系统

系统是基于逍遥商城二开的系统&#xff0c;pc手机端都新增了邀请码验证 手机端重新定制的UI&#xff0c;前端产品不至于抖音卷也可以自行更改其他产品 用户前端下单&#xff0c;后台订单可以直接回收&#xff0c;后台支持设置默认邀请码和抢卷时间限制...

如何选择图片和视频

文章目录 1. 概念介绍2. 方法与细节2.1 实现方法2.2 具体细节 3. 示例代码4. 内容总结 我们在上一章回中介绍了"如何选择视频文件"相关的内容&#xff0c;本章回中将介绍如何混合选择图片和视频文件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我…...

html+css网页制作 电商华为商城首页 ui还原度100%

htmlcss网页制作 电商华为商城首页 ui还原度100% 网页作品代码简单&#xff0c;可使用任意HTML编辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

重启Eureka集群中的节点,对已经注册的服务有什么影响

先看答案&#xff0c;如果正确地操作&#xff0c;重启Eureka集群中的节点&#xff0c;对已经注册的服务影响非常小&#xff0c;甚至可以做到无感知。 但如果操作不当&#xff0c;可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)

目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 &#xff08;1&#xff09;输入单引号 &#xff08;2&#xff09;万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...