泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
通常用T来指代任意输入的类型,除了T
之外,以下是常见泛型变量代表的意思:
- K(Key): 表示对象中键类型;
- V(Value): 表示对象中值类型;
- E(Element): 表示元素类型;
函数中使用泛型
function Person<T>(value: T): T {
return value;
}
console.log(Person<number>(1)) // 1
// 更常见的做法是省略尖括号内的类型变量,编译器会自动选择类型
console.log(Person(1)) // 1
console.log(Person("test")) // "test"
console.log(Person(true)) // true
Person<string>(1) // 1
class中使用泛型
class Person<T>{
name: T
age: number
constructor(name: T, age: number) {
this.name = name
this.age = age
}
}
const p = new Person<string>('张三', 18)
console.log(p.name, p.age) // 张三 18
多个泛型参数
class Person<T, N> {
name: T;
age: N;
job: string;
constructor(name: T, age: N, job: string) {
this.name = name;
this.age = age;
this.job = job;
}
}
const p = new Person<string, number>("张三", 18, "前端开发");
console.log(p); // {name: "张三", age: 18, job: "前端开发"}
泛型参数默认类型
泛型参数的默认类型遵循以下规则:
- 有默认类型的类型参数被认为是可选的。
- 必选的类型参数不能在可选的类型参数后。
- 如果类型参数有约束,类型参数的默认类型必须满足这个约束。
- 当指定类型实参时,你只需要指定必选类型参数的类型实参。未指定的类型参数会被解析为它们的默认类型。
- 如果指定了默认类型,且类型推断无法选择一个候选类型,那么将使用默认类型作为推断结果。
- 一个被现有类或接口合并的类或者接口的声明可以为现有类型参数引入默认类型。
- 一个被现有类或接口合并的类或者接口的声明可以引入新的类型参数,只要它指定了默认类型。
interface A<T = string> {
name: T;
}
let strA: A = { name: "张三" };
let numB: A<number> = { name: 101 };
let strA_1: A = { name: 1 };
泛型约束
可以通过extends 来约束传入的类型
interface IPerson {
name: string;
age: number;
}
function createPerson<T extends IPerson>(person: T) {
return person;
}
interface IUser {
name: string;
age: number;
count: number;
}
createPerson<IUser>({ name: "张三", age: 18, count: 2021 });
console.log(
createPerson<IUser>({ name: "张三", age: 18, count: 2021 })
);//{name: "张三", age: 18, count: 2021}
createPerson<IUser>() // 未提供 "person" 的自变量。