• 规范
  • 普通类型
    • Number,String,Boolean和Object
    • 泛型
  • 回调函数类型
    • 回调函数返回值类型
    • 回调函数里的可选参数
    • 重载与回调函数
  • 函数重载
    • 顺序
    • 使用可选参数
    • 使用联合类型

    规范

    普通类型

    Number,String,Boolean和Object

    不要使用如下类型NumberStringBooleanObject。 这些类型指的是非原始的装盒对象,它们几乎没在JavaScript代码里正确地使用过。

    1. /* 错误 */
    2. function reverse(s: String): String;

    应该使用类型numberstring,and boolean

    1. /* OK */
    2. function reverse(s: string): string;

    使用非原始的object类型来代替Object (TypeScript 2.2新增特性)

    泛型

    不要定义一个从来没使用过其类型参数的泛型类型。 了解详情TypeScript FAQ page。

    回调函数类型

    回调函数返回值类型

    不要为返回值被忽略的回调函数设置一个any类型的返回值类型:

    1. /* 错误 */
    2. function fn(x: () => any) {
    3. x();
    4. }

    应该给返回值被忽略的回调函数设置void类型的返回值类型:

    1. /* OK */
    2. function fn(x: () => void) {
    3. x();
    4. }

    为什么:使用void相对安全,因为它防止了你不小心使用x的返回值:

    1. function fn(x: () => void) {
    2. var k = x(); // oops! meant to do something else
    3. k.doSomething(); // error, but would be OK if the return type had been 'any'
    4. }

    回调函数里的可选参数

    不要在回调函数里使用可选参数除非你真的要这么做:

    1. /* 错误 */
    2. interface Fetcher {
    3. getObject(done: (data: any, elapsedTime?: number) => void): void;
    4. }

    这里有一种特殊的意义:done回调函数可能以1个参数或2个参数调用。 代码大概的意思是说这个回调函数不在乎是否有elapsedTime参数, 但是不需要把这个参数当成可选参数来达到此目的 — 因为总是允许提供一个接收较少参数的回调函数。

    应该写出回调函数的非可选参数:

    1. /* OK */
    2. interface Fetcher {
    3. getObject(done: (data: any, elapsedTime: number) => void): void;
    4. }

    重载与回调函数

    不要因为回调函数参数个数不同而写不同的重载:

    1. /* 错误 */
    2. declare function beforeAll(action: () => void, timeout?: number): void;
    3. declare function beforeAll(action: (done: DoneFn) => void, timeout?: number): void;

    应该只使用最大参数个数写一个重载:

    1. /* OK */
    2. declare function beforeAll(action: (done: DoneFn) => void, timeout?: number): void;

    为什么:回调函数总是可以忽略某个参数的,因此没必要为参数少的情况写重载。 参数少的回调函数首先允许错误类型的函数被传入,因为它们匹配第一个重载。

    函数重载

    顺序

    不要把一般的重载放在精确的重载前面:

    1. /* 错误 */
    2. declare function fn(x: any): any;
    3. declare function fn(x: HTMLElement): number;
    4. declare function fn(x: HTMLDivElement): string;
    5. var myElem: HTMLDivElement;
    6. var x = fn(myElem); // x: any, wat?

    应该排序重载令精确的排在一般的之前:

    1. /* OK */
    2. declare function fn(x: HTMLDivElement): string;
    3. declare function fn(x: HTMLElement): number;
    4. declare function fn(x: any): any;
    5. var myElem: HTMLDivElement;
    6. var x = fn(myElem); // x: string, :)

    为什么:TypeScript会选择第一个匹配到的重载当解析函数调用的时候。 当前面的重载比后面的“普通”,那么后面的被隐藏了不会被调用。

    使用可选参数

    不要为仅在末尾参数不同时写不同的重载:

    1. /* 错误 */
    2. interface Example {
    3. diff(one: string): number;
    4. diff(one: string, two: string): number;
    5. diff(one: string, two: string, three: boolean): number;
    6. }

    应该尽可能使用可选参数:

    1. /* OK */
    2. interface Example {
    3. diff(one: string, two?: string, three?: boolean): number;
    4. }

    注意这在所有重载都有相同类型的返回值时会不好用。

    为什么:有以下两个重要原因。

    TypeScript解析签名兼容性时会查看是否某个目标签名能够使用源的参数调用,且允许外来参数。 下面的代码暴露出一个bug,当签名被正确的使用可选参数书写时:

    1. function fn(x: (a: string, b: number, c: number) => void) { }
    2. var x: Example;
    3. // When written with overloads, OK -- used first overload
    4. // When written with optionals, correctly an error
    5. fn(x.diff);

    第二个原因是当使用了TypeScript“严格检查null”特性时。 因为没有指定的参数在JavaScript里表示为undefined,通常显示地为可选参数传入一个undefined。 这段代码在严格null模式下可以工作:

    1. var x: Example;
    2. // When written with overloads, incorrectly an error because of passing 'undefined' to 'string'
    3. // When written with optionals, correctly OK
    4. x.diff("something", true ? undefined : "hour");

    使用联合类型

    不要为仅在某个位置上的参数类型不同的情况下定义重载:

    1. /* WRONG */
    2. interface Moment {
    3. utcOffset(): number;
    4. utcOffset(b: number): Moment;
    5. utcOffset(b: string): Moment;
    6. }

    应该尽可能地使用联合类型:

    1. /* OK */
    2. interface Moment {
    3. utcOffset(): number;
    4. utcOffset(b: number|string): Moment;
    5. }

    注意我们没有让b成为可选的,因为签名的返回值类型不同。

    为什么:This is important for people who are "passing through" a value to your function:

    1. function fn(x: string): void;
    2. function fn(x: number): void;
    3. function fn(x: number|string) {
    4. // When written with separate overloads, incorrectly an error
    5. // When written with union types, correctly OK
    6. return moment().utcOffset(x);
    7. }