TypeScript泛型与内置工具实现🐍

93 阅读4分钟

本文github地址:JavaScript_Everything 大前端知识体系与面试宝典,从前端到后端,全栈工程师,成为六边形战士


泛型

类型参数化

即便是类型也可以更灵活,使函数更具有通用性,这是由于js本身过于灵活的特性决定的。

function fn<T>(arg: T){
    return arg
}

传入的类型是什么类型,函数fn接收的参数就是什么类型。这可和any不一样,因为any会丢失类型,而泛型是根据传入的参数决定类型,是参数类型的动态化,在调用时决定。

调用时可以不指定函数,ts会自动进行类型推导,而且推导出来的类型会更具体。但这样会增加一些ts编译器的负担,并且推导出来的类型并不总是正确的。

const fn1 = fn<number>(18)
const fn2 = fn('flten')

泛型接口和泛型类

泛型接口,默认指定为string

interface Animal<T = string> {
    name: T,
    age: number,
    food:T,
}

动态决定泛型参数类型
const monkey:Animal<string> = {
    name: 'flten',
    age 18,
    food: 'noodle',
}

泛型类

class Animal<T = string> {
    name: T,
    food: T,
    constructor(name:T, food:T){
        this.name = name
        this.food = food
    }
}

const bird = new Animal('flten', 'pest')

泛型约束

对传入的参数类型结构进行约束,规定必须包含特定属性。

interface hasLength {
    length:number
}
function getLength<T extends hasLength>(arg:<T>):<T>{
    return arg
}

这样就可以记录参数属性的类型。

还可以避免调用时出错,进行强制约束:

function getAnimalProperty<O, K extends keyof O>(obj: O, key: K){
    return obj[key]
}

const bird = {
    name:'bird',
    food:'pest',
}
const birdFood = getAnimalProperty(bird, 'food')

这样就能保证传入的属性一定是存在于对象上的。

内置工具与实现

Partial将类型的属性都变为可选

interface Info {
    name : string,
    age : number,
}

type optionalInfo = Partial<Info>

得到的新类型为:

type optionalInfo = {
    name?: string | undefined;
    age?: number | undefined;
}

实现Partial:使用映射进行属性遍历

type newPartial<T> = {
    [key in keyof T]?: T[key]
}

Rquired将属性的选项都变为必选

interface Info {
    name? : string,
    age? : number,
}

type optionalInfo = Required<Info>

得到新的类型:

type optionalInfo = {
    name: string;
    age: number;
}

自己实现 Required,也是使用映射进行属性遍历

type newRequired<T> = {
    [key in keyof T]-?: T[key]
}

Readonly将类型所有属性都变为readonly只读

interface Info {
    name? : string,
    age? : number,
}

type optionalInfo = Readonly<Info>

得到新的类型:

type optionalInfo = {
    readonly name?: string | undefined;
    readonly age?: number | undefined;
}

自己实现 Readonly:

type newReadonly<T> = {
    readonly [key in keyof T]: T[key]
}

Record<Keys, Types>构造对象类型,规定属性和值的类型

interface Info {
    name? : string,
    age? : number,
}

type k = "a" | "b" | "c"

type optionalInfo = Record<k, Info>

得到的新类型为:

type optionalInfo = {
    a: Info;
    b: Info;
    c: Info;
}

自己实现 Record

type newRecord<K extends keyof Info, V> = {
    [key in K]: V
}

Pick<Type, Types>构造一个类型,并从给定的类型中选出需要的属性

interface Info {
    name? : string,
    age? : number,
}
type optionalInfo = Pick<Info, "name">

得到新的类型为

type optionalInfo = {
    name?: string | undefined;
}

自己实现 Pick

type newPick<T, K extends keyof T> = {
    [p in K]: T[p]
}

Omit<Type, Keys>构造类型,将给定类型中的指定属性进行过滤

interface Info {
    name? : string,
    age? : number,
}
type optionalInfo = Omit<Info, "name">

得到的新类型为:

type optionalInfo = {
    age?: number | undefined;
}

自己实现 Omit

type newOmit<T, K extends keyof T> = {
    [p in keyof T as p extends K ? never : p]: T[p]
}

Exclude<UnionType, ExcludedMembers>将联合类型中的指定类型排除

type k = "a" | "b" | "c"
type optionalInfo = Exclude<k, "a">

得到的新类型为:

type optionalInfo = "b" | "c"

自己实现 Exclude

type newExclude<T, E> = T extends E ? never : T

Extract<UnionType, ExtractMembers>将联合类型中的指定类型保留


type k = "a" | "b" | "c"
type optionalInfo = Extract<k, "a">

得到的新类型为:

type optionalInfo = "a"

自己实现 Extract:

type newExtract<T, E> = T extends E ? T : never

NoneNullable<Type>构造类型,从中排除掉null,undefined类型

type k = "a" | "b" | "c" | null | undefined
type optionalInfo = NonNullable<k>

得到的新类型为:

type optionalInfo = "a" | "b" | "c"

自己实现 NoneNullable:

type newNoneNullable<T> = T extends null | undefined ? never : T

ReturnType<Type>构造一个含有Type函数返回值的类型

下面会取到函数的返回值类型:

function fn():string{
    return 'a'
}

type callbackType = ReturnType<typeof fn>

得到的新类型为:

type callbackType = string

自己实现 ReturnType:

type newReturnType<T extends (...args:any[])=>any> = T extends (...args:any[])=> infer R ? R : never

InstanceType<Type> 取到构造函数的类型

class Animal {}

function factory<T extends new (...args: any[]) => any>(constructor:T):InstanceType<T>{
    return new constructor()
}

const d1 = factory(Animal)

这样就能保证d1类型的正确

const d1: Animal

自己实现 InstanceType:

type newInstanceType<T extends new (...args:any[])=>any> = T extends new (...args:any[])=> infer R ? R : never

本文github地址:JavaScript_Everything 大前端知识体系与面试宝典,从前端到后端,全栈工程师,成为六边形战士