在 C# 和 Java 中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。这样用户就可以以自己的数据类型来使用组件。
设计泛型的关键目的是在成员之间提供有意义的约束,这些成员可以是:类的实例成员、类的方法、函数参数、函数返回值。
泛型是允许同一个函数接受不同类型参数的一种模板。和 any
相比,使用泛型来创建可复用的组件要更好,因为泛型会保留参数类型。
# 泛型语法
代码语言:javascript复制// <T> 用于传递类型
// 可以链式传递给参数类型和返回类型
function identity <T>(value: T): T {
return value;
}
<T>
中的 T
称类型变量,是希望传递给 identity 函数的类型占位符,同时它被分配给 value
参数来代替它的类型。
T
代表 Type,在定义泛型时通常用作第一个类型变量名称。实际上 T
可以用任何有效名称代替。
- K(Key):表示对象中的键类型
- V(Value):表示对象中的值类型
- E(Element):表示元素类型
不只能定义一个类型变量,可以引入希望定义的任何数量的类型变量。
代码语言:javascript复制function identity <T, U>(value: T, message: U): T {
console.log(message);
return value;
}
console.log(identity<Number, string>(2022, 'cell'));
除了为类型变量显示设定值之外,更常见的是使编译器自动选择这些类型,从而使代码更简洁。
代码语言:javascript复制function identity <T, U>(value: T, message: U): T {
console.log(message);
return value;
}
console.log(identity(2022, 'cell'));
# 泛型接口
代码语言:javascript复制interface GenericIdentityFn<T> {
(arg: T): T;
}
# 泛型类
代码语言:javascript复制class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x y; };
# 泛型工具类型
# typeof
typeof
用来获取一个变量声明或对象的类型。
interface Person {
name: string;
age: number;
}
const p: Person = {
name: 'cell',
age: 18,
};
type PersonType = typeof p; // Person
function toArray(x: number): Array<number> {
return [x];
}
type Func = typeof toArray; // (x: number) => number[]
# keyof
keyof
用于获取某类型的所有键,其返回类型是联合类型。
interface Person {
name: string;
age: number;
}
type K1 = keyof Person; // "name" | "age"
type K2 = keyof Person[]; // "length" | "push" | "pop" | "concat" | ...
type K3 = keyof { [x: string]: Person }; // string | number
在 TypeScript 中支持两种索引签名,数字索引和字符串索引:
代码语言:javascript复制interface StringArray {
[index: string]: string; // 字符串索引 keyof StringArray => string | number
}
interface StringArray1 {
[index: number]: string; // 数字索引 keyof StringArray1 => number
}
为了同时支持两种索引类型,要求数字索引的返回值必须是字符串索引返回值的子类。原因是当使用数值索引时,JavaScript 在执行索引操作时,会先把数值索引先转换为字符串索引。所以,keyof { [x: string]: Person }
的结果会返回 string | number
。
# in
in
用来遍历枚举类型
type Keys = "a" | "b" | "c";
type Obj = {
[p in Keys]: any;
}; // { a: any, b: any, c: any }
# infer
在条件类型语句中,可以用 infer
声明一个类型变量并进行使用。
type ReturnType<T> = T extends (
...args: any[]
) => infer R
? R
: any;
# extends
可以使用 extends
添加泛型约束。
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length);
return arg;
}
loggingIdentity(1); // Error because number doesn't have a .length property
loggingIdentity({ length: 10, value: 3 }); // OK
# Partial
Partial<T>
的作用就是将某个类型里的属性全部变为可选项 ?
。
type Partial<T> = {
[P in keyof T]?: T[P];
};
代码语言:javascript复制
interface Todo {
title: string;
description: string;
}
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
return { ...todo, ...fieldsToUpdate };
}
const todo1 = {
title: "Learn TypeScript",
description: "study hard",
};
const todo2 = updateTodo(todo1, {
description: "keep on studying",
});