May 07, 2021 TypeScript
1. Number String Boolean Object
3. The callback function returns the value type
4. Optional arguments in the callback function
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.
Do not define a generic type that has never used its type parameters. Learn more about TypeScript FAQ page.
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'
}
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;
}
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.
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.
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");
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);
}