6. 泛型

51 阅读2分钟
  • 函数参数泛型:在 () 前声明
function createArray<U>(len: number, val: U) {
    let result = [] as U[]
    for (let i = 0; i < len; i++){
        result.push(val)
    }
    return result
}
createArray<100>(3, 100) // [100,100,100]

const createArray = <U>(len: number, val: U) => {
    let result = [] as U[]
    for (let i = 0; i < len; i++){
        result.push(val)
    }
    return result
}
createArray<100>(3, 100) // [100,100,100]
  • 多个泛型
// 2个泛型
function swap<T,K>(tuple:[T,K]):[K,T] {
    return [tuple[1],tuple[0]]
}
swap([1, 'a']) // ['a',1]
  • 泛型的位置对类型推断的影响
1. IFun<T> 表示使用接口的时候确定类型
interface IFun<T>{
    (a:T,b:T):T;
}
let fun:IFun<number> = (a,b)=>{return a+b};

fun('1','2') // ts 错误:string 不能赋值给 number

2. <T>():void 表示使用函数的时候传入类型
interface IFun {
    <T>(a: T, b: T): void;
}

let fun: IFun = <T>(a: T, b: T) => { console.log(a,b) };

fun(1,2)

案例2// 调用时自动推断
type ICallback<T> = (item: T, index: number) => void  // 使用类型的时候传递类型,自动推断类型

type IForeach = <T>(arr: T[], callback: ICallback<T>) => void

const forEach: IForeach = (arr,callback) => {
    for (let i = 0; i < arr.length; i++){
        callback(arr[i],i) // ts 代码并没有执行到这里
    }
}

forEach([1, 2, '3', 4, 5], (item) => { // item: string | number
})


// 需要传递类型,直接调用函数推断不出来 ICallback 的类型,因为 类型推断没有执行 callback(arr[i])
type ICallback = <T>(item: T) => void // 执行的时候传递类型

type IForeach = <T>(arr: T[], callback: ICallback) => void

const forEach: IForeach = (arr,callback) => {
    for (let i = 0; i < arr.length; i++){
        callback(arr[i])
    }
}

forEach(['1',2,'3'],(item) => { // (parameter) item: T
    console.log(item)
})
  • 泛型联合类型
type IUnion<T = boolean> = T | string | number
type t1 = IUnion // string | number | boolean
type t2 = IUnion<string[] | number[]> // string | number | string[] | number[]
  • 泛型约束
// 泛型约束,限制传递的类型符合要求,XXX extends B,XXX 是 B 的子类型
function handle<T extends string>(val:T):T {
    return val
}
handle('abc')


interface IWithLen{
    length:number
}
function handle<T extends IWithLen>(val:T) {
    console.log(val.length)
}
// 子类是父类的扩充
handle({
    a: 1,
    b: 2,
    length: 2
})
  • 类中使用泛型
class MyList<T extends string | number = number> {
    arr: T[] = [];
    add(val: T) {
        this.arr.push(val);
    }
}

const list = new MyList<number>()
list.add(1)
// 类型提示
function getValue<T>(obj:T,key:keyof T) {
    return obj[key]
}

getValue({
    name: '章',
    age:18
}, 'name') // 会有类型提示

function getValue<T extends { name: string; age: number }>(obj: T, key: keyof T): T[keyof T] {
    return obj[key];
}