Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

TypeScript declares the file specification


May 07, 2021 TypeScript


Table of contents


TypeScript declares file specifications

Normal type

Number String Boolean Object

Do not use number, Number Boolean of the Object String These types refer to non-original boxed objects that are barely used correctly in JavaScript code.

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

You should use number string and boolean

/* OK */
function reverse(s: string): string;

If you want to Object type, consider any Currently, an object "is not an original value" cannot be specified in TypeScript.

Generic

Do not define a generic type that has never used its type parameters. Learn more about TypeScript FAQ page.

The type of callback function

The callback function returns the value type

Do not set an any type of return value type for a any function that returns a value that is ignored:

/* 错误 */
function fn(x: () => any) {
    x();
}

The return value type of the void type should be set for the callback function where the return value is ignored:

/* OK */
function fn(x: () => void) {
    x();
}

Why: Using void relatively safe because it prevents you from accidentally using the return value of x

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

Optional arguments in the callback function

Do not use optional parameters in callback functions unless you really want to do so:

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

There is a special meaning here: done callback function may be called with 1 or 2 arguments. The code probably means that this callback function doesn't care elapsedTime parameter, but you don't need to use this argument as an optional argument to do this -- because it always allows for a callback function that receives fewer arguments.

Non-optional parameters for callback functions should be written out:

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

Overload and callback functions

Do not write different overloads because the number of callback function parameters is different:

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

You should write an overload with only the maximum number of parameters:

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

Why: Callback functions can always ignore an argument, so there is no need to override for cases where there are fewer arguments. Callback functions with fewer parameters first allow functions of the wrong type to be passed in because they match the first overload.

The function is overloaded

Order

Do not put ordinary overloads in front of precise overloads:

/* 错误 */
declare function fn(x: any): any;
declare function fn(x: HTMLElement): number;
declare function fn(x: HTMLDivElement): string;

var myElem: HTMLDivElement;
var x = fn(myElem); // x: any, wat?

You should sort overload orders precisely before the general:

/* OK */
declare function fn(x: HTMLDivElement): string;
declare function fn(x: HTMLElement): number;
declare function fn(x: any): any;

var myElem: HTMLDivElement;
var x = fn(myElem); // x: string, :)

Why: TypeScript selects the first match to the overload when the resolution function is called. The current face is overloaded more "normal" than the back, then the back is hidden and will not be called.

Use optional parameters

Do not write different overloads only for different parameters at the end:

/* 错误 */
interface Example {
    diff(one: string): number;
    diff(one: string, two: string): number;
    diff(one: string, two: string, three: boolean): number;
}

Optional parameters should be used as far as possible:

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

Note that this is not useful when all overloads have the same type of return value.

Why: There are two reasons to be born.

TypeScript resolves signature compatibility to see if a target signature can be called using the source's parameters, and foreign parameters are allowed. The following code exposes a bug when the signature is correctly written using optional parameters:

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

The second reason is when you use TypeScript to "strictly check the null" feature. B ecause no specified parameters are represented undefined an undefined is usually passed in as an optional parameter. This code works in strict null mode:

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

Use the union type

Do not define overloads only if the parameter types at a certain location are different:

/* WRONG */
interface Moment {
    utcOffset(): number;
    utcOffset(b: number): Moment;
    utcOffset(b: string): Moment;
}

Type types should be used as much as possible:

/* OK */
interface Moment {
    utcOffset(): number;
    utcOffset(b: number|string): Moment;
}

Note that we b make b optional because the return value type of the signature is different.

Why: This is important for people who are "passing through" value to your function:

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