对于一个工作代码库,TS 有不同严格等级的类型系统。

  • 仅仅基于 JS 代码的类型推断
  • 在 JS 中使用 JSDoc 来逐步增加类型
  • 在 JS 文件中使用 // @ts-check
  • 使用 TS 代码
  • 在 TS 中使用严格模式

    对 JS 文件使用 TS 编译器

    TS 编译器也可以处理纯 JS 文件:

  • 使用 —allowJs 选项,TS 编译器可以将输入文件夹中的 JS 文件复制到输出文件夹。优点:当把 JS 代码迁移到 TS 代码的时候,可以混合使用两种代码文件,逐步完成迁移

  • 使用 —checkJs 选项,编译器会逐步对 JS 文件进行类型检查。可以使用 // @ts-check// @ts-nocheck 对不同的代码块进行针对性的设置
  • 使用 JSDoc 进行类型注释
  • 使用 --noEmit 参数,编译器只对文件进行类型检查,而不输出任何文件

    对 JS 文件使用类型检查

    @type

    ```typescript /* @type {HTMLElement} / const myElement = document.querySelector(selector); element.dataset.myData = “”;

/* @type {(string | boolean)} / const stringOrBoolean = true

/**

  • A map-like object that maps arbitrary string properties to numbers. *
  • @type {Object.} */ var stringToNumber; ``` 可以对变量设置固定的类型,或者设置联合类型。联合类型中的括号是可选的。

    @param 和 @returns

    ```typescript // Parameters may be declared in a variety of syntactic forms /**
  • @param {string} p1 - A string param.
  • @param {string=} p2 - An optional param (Closure syntax)
  • @param {string} [p3] - Another optional param (JSDoc syntax).
  • @param {string} [p4=”test”] - An optional param with a default value
  • @return {string} This is the result */ function stringsStringStrings(p1, p2, p3, p4) { // TODO } ```

    @template

    使用 @template 来声明泛型函数 ```typescript /**
  • @template T
  • @param {T} x - A generic parameter that flows through to the return type
  • @return {T} */ function id(x) { return x; }

const a = id(“string”); const b = id(123); const c = id({});

  1. <a name="AsG8J"></a>
  2. ### @enum
  3. 使用 `@enum` 来模拟枚举类型
  4. ```typescript
  5. /** @enum {number} */
  6. const JSDocState = {
  7. BeginningOfLine: 0,
  8. SawAsterisk: 1,
  9. SavingComments: 2,
  10. };
  11. JSDocState.SawAsterisk;

JS Class extensions

用来模拟 @public , @private , @protected

// @ts-check

class Car {
  constructor() {
    /** @private */
    this.identifier = 100;
  }

  printIdentifier() {
    console.log(this.identifier);
  }
}

const c = new Car();

函数参数是默认可选的

/**
 * @param {string} [somebody] - Somebody's name.
 */
function sayHello(somebody) {
  if (!somebody) {
    somebody = "John Doe";
  }
  console.log("Hello " + somebody);
}

sayHello();

使用 [] 来使得参数可选

使用 var-args 参数声明来对 arguments 的使用来进行推断

/** @param {...number} args */
function sum(/* numbers */) {
  var total = 0;
  for (var i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
}

在 extends clause

使用 @augments 来显式指定类型

import { Component } from "react";
/**
 * @augments {Component<{a: number}, State>}
 */
class MyComponent extends Component {
  render() {
    this.props.b; // Error: b does not exist on {a:number}
  }
}

未设定的参数默认为 any

/** @type{Array} */
var x = [];

x.push(1); // OK
x.push("string"); // OK, x is of type Array<any>

/** @type{Array.<number>} */
var y = [];

y.push(1); // OK
y.push("string"); // Error, string is not assignable to number

参考