一、泛型程序设计是一种编程风格或编程范式
二、案例:传入的参数类型与返回的类型一样
function identify<T>(arg: T): T {// 当前的T没有任何约束 它可以是任何类型
return arg;
}
const foo = identify('foo'); // foo的类型是'foo'
const bar = identify('true'); // bar的类型是true
三、形式类型参数
1、形式类型参数T的默认类型为boolean类型
<T = boolean>
2、必选类型参数、可选类型参数
(1)、必选类型参数:形式类型参数没有给默认类型 , 例如: <T>
(2)、可选类型参数:形式类型参数给默认类型 , 例如: <T = boolean>
(3)、形式类型参数列表中,必选类型参数不允许出现在可选类型参数之后
<T = boolean, U> // 错误
<T, U = boolean> // 正确
四、泛型约束
在形式类型参数上允许定义一个约束条件,它能够限定类型参数的实际类型的最大范围。我们将类型参数的约束条件称为泛型约束
interface point {
x: number,
y: string
}
function getPoint<T extends point>(args: T): T {
return args
}
console.log(getPoint({x: 123, y: 456})); // 错误
console.log(getPoint({x: 123, y: '456'})); // 正确
console.log(getPoint({x: 123, y: '456', z: 678})); // 正确
//参数的前俩个必须有并且类型必须正确 否则错误
可以同时定义泛型约束和默认类型
<T extends number = 0 | 1>
泛型约束 ==> 类型参数
<T, U extends T>
<T extends U, U>
形式类型参数不允许直接或间接地将其自身作为约束类型
<T extends T> // 错误
<T extends U, U extends T> // 错误
类型参数T没有声明泛型约束,那么类型参数T的基约束为空对象类型字面量“{}”。除了undefined类型和null类型外,其他任何类型都可以赋值给空对象类型字面量
<T> // 类型参数T的基数约为“{}”类型
五、泛型函数
1.简介:若一个函数的函数签名(形参)中带有类型参数,那么它是一个泛型函数
2.f1函数两个参数的类型相同,函数返回值类型是数组,数组元素类型 == 参数类型。
function f1<T>(x: T, y: T): T[] {
return [x, y]
}
const a = f1(123, 456)
const b = f1('123', '456')
3.f2函数两个参数的类型不同,返回值类型为对象类型。返回值对象类型中x属性的类型与参数x类型相同,y属性的类型与参数y类型相同
function f2<T, U>(x: T, y: U): { x: T, y: U} {
return { x, y }
}
const a = f2('123', 456)
const b = f2(123, '456')
4.f3函数接受两个参数,参数a为任意类型的数组;参数f是一个函数,该函数的参数类型与参数a的类型相同,并返回任意类型。f3函数的返回值类型为参数f返回值类型的数组。
(这个代码的粘贴的 我也懵逼)
function f3<T, U>(a: T[], f: (x: T) => U): U[] {
return a.map(f);
}
// f3<number, boolean> 约束T为number类型 U为boolean类型
const a: boolean[] = f3<number, boolean>([1, 2, 3], n => !! n)
六、泛型函数类型推断
function f0<T>(x: T): T {
return x
}
const a = f0(123) // 推断出类型为 123
const b = f0('123') // 推断出类型为 '123'
此例中编译器推断出的不是number 和 string类型,而是字符串字面量类型123和“123”。因为TS原则,始终将字面量视为字面量类型,只在必要的时候才会将字面量类型放宽为某种基础类型,例如string类型。此例中,字符串字面量类型“123”是比string类型更加精确的类型。
类型参数只在函数签名中出现一次,则说明它与其他值没有关联,则不需要使用类型参数,直接声明实际类型即可。
几乎任何函数都可以声明为泛型函数。若泛型函数的类型参数不表示参数之间或参数与返回值之间的某种关系,那么使用泛型函数可能是一种反模式。
// 没必要使用泛型
function f<T>(x: T): void {
console.log(x)
}
// 直接限定就好了
function f(x: number): void {
console.log(x)
}