头图

Typescript 高阶类型

  • 索引类型 keyof 会提取interface中的key

    class KeyCls {
    name: string
    age: number
    }
    type KeyClsExample1 = keyof KeyCls // name | age
    
    function getParams(params: keyof KeyCls) {}
    
    getParams('name') // 正常
    getParams('age') // 正常
    getParams('sex') // 报错
  • in 可以遍历枚举类型

    type Keys = 'a' | 'b'
    type Obj = {
    [p in Keys]: any;
    }
    
    // type Obj = {
    //     a: any;
    //     b: any;
    // }
  • extends

    type TExtends<T, U> = T extends U ? number : never;
    type TExtendExample = TExtends<number, number | string> // number
    
    
    // 联合类型, 表示如果T中的类型是U的子集, 那么返回never, 否则返回T, 这个过程可以理解为对T中的类型进行一次遍历, 每个类型都执行一次extends
    type NonNullable1<T, U> = T extends U ? never : T
    type NonExample = NonNullable1<null | string, null | undefined> // string
  • Pick 英文意思挑选, 也就是从某种类型中挑选出一个或多个属性

    interface Todo {
    title: string
    desc: string
    Done: boolean
    }
    
    type TodoPreview = Pick<Todo, 'Done'>
    // type TodoPreview = {
    //     Done: boolean;
    // }
    
    // 实现
    type MyPick<T, K extends keyof T = keyof T> = {
    [P in K]: T[P]
    }
    // K in extends keyof T = keyof T, 意思是取值必须是在T的key上面取, 如果不传递取值默认为keyof T,所有的key, 内部取值是如果传递了K, 则属性就在K中任意一个
  • Readonly 只读

    interface Todo {
    title: string
    desc: string
    Done: boolean
    }
    const todo: Pick<Readonly<Todo>, 'title'> = {
    title: '你好'
    }
    
    todo.title = '啊啊啊'; // 无法为“title”赋值,因为它是只读属性
    
    // 实现
    type myReadonly<T> = {
    readonly [K in keyof T]: T[K]
    }
    // 分析: 通过keyof拿到所有的key属性值组成联合类型, 然后通过in遍历类型,在属性值前面加上readonly, 值value则是 T[K]
    
    // 通过上面案例还可以实现可选类型
    
    type myOptional<T> = {
    [K in keyof T]?: T[K]
    }
  • Exclude 语法: Exclude<T, U>, 返回 T 中不存在于 U 的部分

    // 回顾extends
    // // 联合类型, 表示如果T中的类型是U的子集, 那么返回never, 否则返回T, 这个过程可以理解为对T中的类型进行一次遍历, 每个类型都执行一次extends
    // type NonNullable1<T, U> = T extends U ? never : T
    // type NonExample = NonNullable1<null | string, null | undefined> // string
    
    // 自己实现Exclude
    type myExclude<T, U> = T extends U ? never : T
    
    // 测试
    // 分析: 对T也就是'a'|'b'遍历, a extends 'a'|'b', 返回never, 'b', 'a'|'c',返回'b', 所以上面的返回'b'
    type excludeExample = myExclude<'a' | 'b', 'a' | 'c'> // 'b'
  • Partial 将传入的属性变为可选项

    
    interface Todo {
    title: string
    desc: string
    Done: boolean
    }
    
    
    
    type Partial<T> = {
    [P in keyof T]?: T[P]
    }
    
    type KeyOfExample1 = Partial<Todo>
    let keyofEx1: KeyOfExample1 = {
    title: '1'
    }
  • -? 将可选项代表的 ?去掉, 将该类型变成必选项, 与之对应的还有一个+?,是将可选项变成必选项

    
    interface Todo {
    title: string
    desc: string
    Done: boolean
    }
    
    type Mutable<T> = {
    -readonly [P in keyof T]: T[P]
    }
    
    type mutableExample = Mutable<Readonly<Todo>>
    // 将Todo变成可读之后再变成可写
  • Required 将传入的属性变成必选项

    type Required<T> = {
    [P in keyof T]-?: T[P]
    }
    
    class KeyCls {
    name?: string;
    age?: number;
    }
    
    const requiredExample: Required<KeyCls> = {
    name: "John",
    } // 报错
    const requiredExample2: Required<KeyCls> = {
    name: "John",
    age: 20,
    } // 正常
  • Record<K, T> 将K中所有的属性转化为T类型

    type myRecord<K extends keyof any, T> = {
    [P in K]: T
    }
    
    enum Methods {
    GET = "get",
    POST = "post",
    DELETE = "delete",
    PUT = "put",
    }
    
    type IRouter = myRecord<Methods, (req: any, res: any) => void>
    
    // type IRouter = {
    //     get: (req: any, res: any) => void;
    //     post: (req: any, res: any) => void;
    //     delete: (req: any, res: any) => void;
    //     put: (req: any, res: any) => void;
    // }
  • Omit 排除某些字段

    // 已经学习了Pick和Exclude, 则可以利用这两个实现Omit
    
    class KeyCls {
    name: string;
    age: number;
    }
    
    // 假设 T 为 KeyCls, K为name, 结果是 
    // type myOmit<KeyCls, 'name'>
    // {  
    //    age: number;  
    // }
    
    // 只需要实现成这样就行了, 也就是获取到age
    type myOmit<T, K extends keyof T> = Pick<T, 'age'>
    
    // 排除name, 按照上面的 Exclude<'name' | 'age', 'name'> // 'age'
    type myOmit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>
    
    // 测试
    
    type myOmitExample = myOmit<KeyCls, "name">;
    
    // type myOmitExample = {  
    //     age: number;  
    // }
  • NonNullable<T>:作用是去掉 T 中的 null 和 undefined。T 为字面量/具体类型的联合类型

    // 4.8版本之前
    type NonNullable<T> = T extends null | undefined ? never : T;
      
    // 4.8版本之后
    type NonNullable<T> = T & {}
  • infer 可以推荐一个类型变量, 相当于生命一个类型变量, 这个变量的类型取决于传入的泛型T

    type F<T> = T extends () => infer R ? R : T;
    type F1 = F<string> // string
    type TObj<T> = T extends { name: infer V, age: infer U } ? V : T
    type TObjExample2 = TObj<{
    name: number;
    age: string;
    }>; // number;
  • ReturnType<T> 获取函数返回值的类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
    
functin getUser() {
    return {
        name: 'xxx',
        age: 20
    }
}
    
type GetUserType = typeof getUser;
// type GetUserType = () => {
//   name: string;
//   age: number;
// }
    
type ReturnUser = ReturnType<GetUserType>
type ReturnUser = {
//   name: string;
//   age: number;
// }

。。。嗯
5 声望0 粉丝