• 【TS】546- 掌握 TS 这些工具类型,让你开发事半功倍


    创建了一个“重学TypeScript”的微信群,想加群的小伙伴,加我微信 "semlinker",备注重学TS。

    一、类型别名

    TypeScript 提供了为类型注解设置别名的便捷语法,你可以使用 type SomeName = someValidTypeAnnotation 来创建别名,比如:

    type Pet = 'cat' | 'dog';
    let pet: Pet;
    
    pet = 'cat'; // Ok
    pet = 'dog'; // Ok
    pet = 'zebra'; // Compiler error
    

    二、基础知识

    为了让大家能更好地理解并掌握 TypeScript 内置类型别名,我们先来介绍一下相关的一些基础知识。

    2.1 typeof

    在 TypeScript 中,typeof 操作符可以用来获取一个变量声明或对象的类型。

    interface Person {
      name: string;
      age: number;
    }
    
    const sem: Person = { name: 'semlinker', age: 30 };
    type Sem= typeof sem; // -> Person
    
    function toArray(x: number): Array<number> {
      return [x];
    }
    
    type Func = typeof toArray; // -> (x: number) => number[]
    

    继续阅读:TypeScript typeof 操作符

    2.2 keyof

    keyof 操作符可以用来一个对象中的所有 key 值:

    interface Person {
        name: string;
        age: number;
    }
    
    type K1 = keyof Person; // "name" | "age"
    type K2 = keyof Person[]; // "length" | "toString" | "pop" | "push" | "concat" | "join"
    type K3 = keyof { [x: string]: Person };  // string | number
    

    继续阅读:TypeScript keyof 操作符

    2.3 in

    in 用来遍历枚举类型:

    type Keys = "a" | "b" | "c"
    
    type Obj =  {
      [p in Keys]: any
    } // -> { a: any, b: any, c: any }
    

    继续阅读:在 TS 中如何实现类型保护?类型谓词了解一下

    2.4 infer

    在条件类型语句中,可以用 infer 声明一个类型变量并且对它进行使用。

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

    以上代码中 infer R 就是声明一个变量来承载传入函数签名的返回值类型,简单说就是用它取到函数返回值的类型方便之后使用。

    继续阅读:用上这几招,轻松实现 TS 类型提取

    2.5 extends

    有时候我们定义的泛型不想过于灵活或者说想继承某些类等,可以通过 extends 关键字添加泛型约束。

    interface ILengthwise {
      length: number;
    }
    
    function loggingIdentity<T extends ILengthwise>(arg: T): T {
      console.log(arg.length);
      return arg;
    }
    

    现在这个泛型函数被定义了约束,因此它不再是适用于任意类型:

    loggingIdentity(3);  // Error, number doesn't have a .length property
    

    这时我们需要传入符合约束类型的值,必须包含必须的属性:

    loggingIdentity({length: 10, value: 3});
    

    三、内置类型别名

    3.1 Partial

    Partial<T> 的作用就是将某个类型里的属性全部变为可选项 ?

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * Make all properties in T optional
     */
    type Partial<T> = {
        [P in keyof T]?: T[P];
    };
    

    在以上代码中,首先通过 keyof T 拿到 T 的所有属性名,然后使用 in 进行遍历,将值赋给 P,最后通过 T[P] 取得相应的属性值。中间的 ?,用于将所有属性变为可选。

    示例:

    interface Todo {
      title: string;
      description: string;
    }
    
    function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
      return { ...todo, ...fieldsToUpdate };
    }
    
    const todo1 = {
      title: "organize desk",
      description: "clear clutter"
    };
    
    const todo2 = updateTodo(todo1, {
      description: "throw out trash"
    });
    

    3.2 Required

    Required<T> 的作用就是将某个类型里的属性全部变为必选项。

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * Make all properties in T required
     */
    type Required<T> = {
        [P in keyof T]-?: T[P];
    };
    

    以上代码中,-? 的作用就是移除可选项 ?

    示例:

    interface Props {
      a?: number;
      b?: string;
    }
    
    const obj: Props = { a: 5 }; // OK
    const obj2: Required<Props> = { a: 5 }; // Error: property 'b' missing
    

    3.3 Readonly

    Readonly<T> 的作用是将某个类型所有属性变为只读属性,也就意味着这些属性不能被重新赋值。

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * Make all properties in T readonly
     */
    type Readonly<T> = {
        readonly [P in keyof T]: T[P];
    };
    

    如果将上面的 readonly 改成 -readonly, 就是移除子属性的 readonly 标识。

    示例:

    interface Todo {
      title: string;
    }
    
    const todo: Readonly<Todo> = {
      title: "Delete inactive users"
    };
    
    todo.title = "Hello"; // Error: cannot reassign a readonly property
    

    Readonly<T> 对于表示在运行时将赋值失败的表达式很有用(比如,当尝试重新赋值冻结对象的属性时)。

    function freeze<T>(obj: T): Readonly<T>;
    

    3.4 Record

    Record<K extends keyof any, T> 的作用是将 K 中所有的属性的值转化为 T 类型。

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * Construct a type with a set of properties K of type T
     */
    type Record<K extends keyof any, T> = {
        [P in K]: T;
    };
    

    示例:

    interface PageInfo {
      title: string;
    }
    
    type Page = "home" | "about" | "contact";
    
    const x: Record<Page, PageInfo> = {
      about: { title: "about" },
      contact: { title: "contact" },
      home: { title: "home" }
    };
    

    3.5 Pick

    Pick<T, K extends keyof T> 的作用是将某个类型中的子属性挑出来,变成包含这个类型部分属性的子类型。

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * From T, pick a set of properties whose keys are in the union K
     */
    type Pick<T, K extends keyof T> = {
        [P in K]: T[P];
    };
    

    示例:

    interface Todo {
      title: string;
      description: string;
      completed: boolean;
    }
    
    type TodoPreview = Pick<Todo, "title" | "completed">;
    
    const todo: TodoPreview = {
      title: "Clean room",
      completed: false
    };
    

    3.6 Exclude

    Exclude<T, U> 的作用是将某个类型中属于另一个的类型移除掉。

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * Exclude from T those types that are assignable to U
     */
    type Exclude<T, U> = T extends U ? never : T;
    

    如果 T 能赋值给 U 类型的话,那么就会返回 never 类型,否则返回 T 类型。最终实现的效果就是将 T 中某些属于 U 的类型移除掉。

    示例:

    type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"
    type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // "c"
    type T2 = Exclude<string | number | (() => void), Function>; // string | number
    

    3.7 Extract

    Extract<T, U> 的作用是从 T 中提取出 U

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * Extract from T those types that are assignable to U
     */
    type Extract<T, U> = T extends U ? T : never;
    

    如果 T 能赋值给 U 类型的话,那么就会返回 T 类型,否则返回 never 类型。

    示例:

    type T0 = Extract<"a" | "b" | "c", "a" | "f">; // "a"
    type T1 = Extract<string | number | (() => void), Function>; // () => void
    

    3.8 Omit

    Omit<T, K extends keyof any> 的作用是使用 T 类型中除了 K 类型的所有属性,来构造一个新的类型。

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * Construct a type with the properties of T except for those in type K.
     */
    type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
    

    示例:

    interface Todo {
      title: string;
      description: string;
      completed: boolean;
    }
    
    type TodoPreview = Omit<Todo, "description">;
    
    const todo: TodoPreview = {
      title: "Clean room",
      completed: false
    };
    

    3.9 NonNullable

    NonNullable<T> 的作用是用来过滤类型中的 nullundefined 类型。

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * Exclude null and undefined from T
     */
    type NonNullable<T> = T extends null | undefined ? never : T;
    

    示例:

    type T0 = NonNullable<string | number | undefined>; // string | number
    type T1 = NonNullable<string[] | null | undefined>; // string[]
    

    3.10 ReturnType

    ReturnType<T> 的作用是用于获取函数 T 的返回类型。

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * Obtain the return type of a function type
     */
    type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
    

    示例:

    type T0 = ReturnType<() => string>; // string
    type T1 = ReturnType<(s: string) => void>; // void
    type T2 = ReturnType<<T>() => T>; // {}
    type T3 = ReturnType<<T extends U, U extends number[]>() => T>; // number[]
    type T4 = ReturnType<any>; // any
    type T5 = ReturnType<never>; // any
    type T6 = ReturnType<string>; // Error
    type T7 = ReturnType<Function>; // Error
    

    继续阅读:用上这几招,轻松实现 TS 类型提取

    3.11 InstanceType

    InstanceType 的作用是获取构造函数类型的实例类型。

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * Obtain the return type of a constructor function type
     */
    type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;
    

    示例:

    class C {
      x = 0;
      y = 0;
    }
    
    type T0 = InstanceType<typeof C>; // C
    type T1 = InstanceType<any>; // any
    type T2 = InstanceType<never>; // any
    type T3 = InstanceType<string>; // Error
    type T4 = InstanceType<Function>; // Error
    

    3.12 ThisType

    ThisType<T> 的作用是用于指定上下文对象的类型。

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * Marker for contextual 'this' type
     */
    interface ThisType<T> { }
    

    注意:使用 ThisType<T> 时,必须确保 --noImplicitThis 标志设置为 true。

    示例:

    interface Person {
        name: string;
        age: number;
    }
    
    const obj: ThisType<Person> = {
      dosth() {
        this.name // string
      }
    }
    

    继续阅读:TypeScript 中神奇的 this 类型声明

    3.13 Parameters

    Parameters<T> 的作用是用于获得函数的参数类型组成的元组类型。

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * Obtain the parameters of a function type in a tuple
     */
    type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any 
      ? P : never;
    

    示例:

    type A = Parameters<() => void>; // []
    type B = Parameters<typeof Array.isArray>; // [any]
    type C = Parameters<typeof parseInt>; // [string, (number | undefined)?]
    type D = Parameters<typeof Math.max>; // number[]
    

    3.14 ConstructorParameters

    ConstructorParameters<T> 的作用是提取构造函数类型的所有参数类型。它会生成具有所有参数类型的元组类型(如果 T 不是函数,则返回的是 never 类型)。

    定义:

    // node_modules/typescript/lib/lib.es5.d.ts
    
    /**
     * Obtain the parameters of a constructor function type in a tuple
     */
    type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;
    

    示例:

    type A = ConstructorParameters<ErrorConstructor>; // [(string | undefined)?]
    type B = ConstructorParameters<FunctionConstructor>; // string[]
    type C = ConstructorParameters<RegExpConstructor>; // [string, (string | undefined)?]
    

    四、参考资源

    • TypeScript 强大的类型别名

    • typescript-3-7-utility-types-printable-pdf-cheat-sheet

    • 深入理解 TypeScript

    原创系列推荐

    1. JavaScript 重温系列(22篇全)

    2. ECMAScript 重温系列(10篇全)

    3. JavaScript设计模式 重温系列(9篇全)

    4. 正则 / 框架 / 算法等 重温系列(16篇全)

    5. Webpack4 入门(上)|| Webpack4 入门(下)

    6. MobX 入门(上) ||  MobX 入门(下)

    7. 59篇原创系列汇总

    回复“加群”与大佬们一起交流学习~

    点这,与大家一起分享本文吧~

    个人博客:http://www.pingan8787.com 微信公众号【前端自习课】和千万网友一起,每日清晨,享受一篇前端优秀文章。 目前已连续推送文章 600+ 天,愿每个人的初心都能一直坚持下去!
  • 相关阅读:
    day3---字符串的索引与切片
    day4---int bool str之间相互转换
    day3---数据类型整体分析
    day2---while else
    day2---运算符
    day2---格式化输出
    ES6-04 Promise设计 类 模块
    jquery02-效果动画
    jquery01-基础使用
    bootstrap-03 常用重要组件(2)
  • 原文地址:https://www.cnblogs.com/pingan8787/p/13069437.html
Copyright © 2020-2023  润新知