函数
类型定义
ts
// 简单形式
function greeter(fn: (a: string) => void) {
fn("Hello, World");
}
// 类型别名
type Fn = (a: string) => void
// 带属性的函数,和对象还是有点不同的
type Fn = {
foo: string,
(a: string): void
}
// 对象类型
type Obj = {
foo: string,
fn: (a: string) => void,
}
// 构造函数
type Fn = {
new (a: string): void
}
// 有些对象,例如 JavaScript 的Date对象,可以使用或不使用new. 您可以任意组合同一类型的调用和构造签名:
interface CallOrConstruct {
new (s: string): Date;
(n?: number): string;
}
// 通用函数,利用泛型实现
function firstElement<Type>(arr: Type[]): Type | undefined {
return arr[0];
}
函数返回值推断
ts
function longest<Type extends { length: number }>(a: Type, b: Type) {
if (a.length >= b.length) {
return a;
} else {
return b;
}
}
// longerArray is of type 'number[]'
const longerArray = longest([1, 2], [1, 2, 3]);
// longerString is of type 'alice' | 'bob'
const longerString = longest("alice", "bob");
// Error! Numbers don't have a 'length' property
const notOK = longest(10, 100);
指定类型参数
ts
function combine<Type>(arr1: Type[], arr2: Type[]): Type[] {
return arr1.concat(arr2);
}
const arr = combine([1, 2, 3], ["hello"]);
// Type 'string' is not assignable to type 'number'.
// 可以手动指定Type
const arr = combine<string | number>([1, 2, 3], ["hello"]);
编写良好泛型函数的指南
ts
function firstElement1<Type>(arr: Type[]) {
return arr[0];
}
function firstElement2<Type extends any[]>(arr: Type) {
return arr[0];
}
// a: number (good)
const a = firstElement1([1, 2, 3]);
// b: any (bad)
const b = firstElement2([1, 2, 3]);
尽可能少的类型参数
ts
// good, 只有一个Type泛型
function filter1<Type>(arr: Type[], func: (arg: Type) => boolean): Type[] {
return arr.filter(func);
}
// bad 有2个泛型 Type和Func
function filter2<Type, Func extends (arg: Type) => boolean>(
arr: Type[],
func: Func
): Type[] {
return arr.filter(func);
}
类型参数应该出现两次
ts
// 这里Str只被用到了一次
function greet<Str extends string>(s: Str) {
console.log("Hello, " + s);
}
greet("world");
// 更简单的版本
function greet(s: string) {
console.log("Hello, " + s);
}
回调中的可选参数
加?即是可选参数,但是调用时确会报错,怎么解决,函数重载
ts
function myForEach(arr: any[], callback: (arg: any, index?: number) => void) {
for (let i = 0; i < arr.length; i++) {
callback(arr[i], i);
}
}
myForEach([1, 2, 3], (a, i) => {
console.log(i.toFixed());
// 'i' is possibly 'undefined'.
});
函数重载
编写一定数量的函数签名(通常是两个或更多),然后是函数体
ts
// 此示例中,我们编写了两个重载:一个接受一个参数,另一个接受三个参数。前两个签名称为重载签名
// 从外部看不到实现的签名。当编写重载函数时,您应该始终在函数的实现之上有两个或多个签名。
function makeDate(timestamp: number): Date; // 函数签名
function makeDate(m: number, d: number, y: number): Date; // 函数签名
function makeDate(mOrTimestamp: number, d?: number, y?: number): Date { // 实际函数体
if (d !== undefined && y !== undefined) {
return new Date(y, mOrTimestamp, d);
} else {
return new Date(mOrTimestamp);
}
}
const d1 = makeDate(12345678);
const d2 = makeDate(5, 5, 5);
const d3 = makeDate(1, 3);
// No overload expects 2 arguments, but overloads do exist that expect either 1 or 3 arguments.
实现签名还必须与重载签名兼容。例如,这些函数有错误,因为实现签名与重载不正确匹配:
ts
function fn(x: boolean): void;
// Argument type isn't right
function fn(x: string): void;
// 实现签名的参数类型与重载签名不兼容
function fn(x: boolean) {}
ts
function fn(x: string): string;
// Return type isn't right
function fn(x: number): boolean;
// 实现签名的返回类型与重载签名不兼容
function fn(x: string | number) {
return "oops";
}
TIP
对于参数个数相同但是类型不同,应优先考虑联合类型而不是重载,可选参数可以优先考虑重载
ts
function len(s: string): number;
function len(arr: any[]): number;
function len(x: any) {
return x.length;
}
function len(x: any[] | string) {
return x.length;
}
在函数中声明this
将this放在第一个参数来定义this的类型,这是定义this的特殊形式,因为this是个关键字,不能充当变量名称
ts
interface DB {
filterUsers(filter: (this: User) => boolean): User[];
}
const db = getDB();
const admins = db.filterUsers(function (this: User) {
return this.admin;
});
其他ts类型
- void // 与undefined不同
- object
- unknown // 与any类似,但是unknown类型不能执行任何属性访问操作
- never
- Function
never
ts
// 返回never意味着函数抛出异常或终止程序
function fn(x: string | number) {
if (typeof x === "string") {
// do something
} else if (typeof x === "number") {
// do something else
} else {
x; // has type 'never'!
}
}
其余参数
ts
// Inferred type is number[] -- "an array with zero or more numbers",
// not specifically two numbers
const args = [8, 5];
const angle = Math.atan2(...args);
// A spread argument must either have a tuple type or be passed to a rest parameter.
// 解决办法
const args = [8, 5] as const; // 将args变成只读元组(tuple)
参数结构
ts
function sum({ a, b, c }: { a: number; b: number; c: number }) {
console.log(a + b + c);
}
// 或者
// Same as prior example
type ABC = { a: number; b: number; c: number };
function sum({ a, b, c }: ABC) {
console.log(a + b + c);
}
函数的可分配性
通过类型别名定义的返回void的函数,其应用时可以不返回void
ts
type voidFunc = () => void;
const f1: voidFunc = () => {
return true; // ok
};
直接定义的返回void的函数类型,不能再返回其他值
ts
function f2(): void {
return true; // error
}
const f3 = function (): void {
return true; // error
};