TypeScript 内置工具类型学习(二)

442 阅读6分钟

「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。

概述

在上篇文章# TypeScript 内置工具类型学习(一)中,介绍 了部分TypeScript的内置工具类型,剩下部分将在这篇文章介绍完毕。

Omit(排除类型中的部分属性)

Omit<T, K extends keyof any>根据传入的条件,来排除掉类型的部分属性,然后组成一个新的类型。 ​

源代码:

/**
 * 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>>;

含义为:从T类型中挑出在K类型中没有的属性,然后组成一个新的类型。

  • 首先使用Exclude排除掉TK当中都有的属性,并返回结果
  • 然后使用Pick从T中挑选出符合返回结果的属性,组成新的类型

代码示例:

在线示例

interface User {
    name: string,
    age: number,
    address: string,
}

/**
    相当于:
    type User1 = {
        name: string;
        age: number;
    }
 */
type User1 = Omit<User, 'address'>;

const user: User1 = {
    name: '金小钗',
    age: 18,
    // address 已被排除,添加会报错
    address: '广州',
}

type User1 = Omit<User, 'address'>的转换过程: ​

  1. Exclude<keyof User, 'address'>
  • keyof User结果为'name' | 'age' | 'address'
  • 排除掉属性address,返回结果为'name' | 'age'
  1. 根据上一步的结果,则有Pick<User, 'name' | 'age'>

返回结果为:

{
  name: string;
  age: number;
}

NonNullable(排除null | undefined类型)

NonNullable可以用来排除掉类型中的null undefined类型,然后返回新类型。 ​

源代码:

/**
 * Exclude null and undefined from T
 */
type NonNullable<T> = T extends null | undefined ? never : T;
  • 这个比较好理解,就是判断是否可以转换为null | undefined类型,然后进行返回

代码示例:

在线示例

type T1 = 'a' | 'b' | null | undefined;
type T2 = NonNullable<T1>;


const a: T1 = null;
const b: T1 = undefined;
// 以下代码报错,因为 null 和 undefined 类型已被去除
const c: T2 = null;
const d: T2 = undefined;

Parameters(使用函数形参创建元组)

Parameters用于推断一个函数类型的形参类型,然后组合成一个有有名称的元组类型。

源代码:

/**
 * 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;
  • 首先T有约束条件,得为一个函数类型
  • 在实际使用的时候,使用infer推断参数的类型并赋值给P
    • infer需要跟extends配合使用
  • 返回的P类型是个有名称的元组

代码示例:

在线示例

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

type Foo = (user: User) => void;

/**
 最终结果:
 type P = [user: User]
 */
type P = Parameters<Foo>;

const user = {
    name: '金小钗',
    age: 18,
}
const a: P = [user];

更多例子:

ReturnType(获取函数返回值类型)

ReturnType可以用来获取一个函数的返回值类型。 ​

源代码:

/**
 * Obtain the return type of a function type
 */
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
  • 首先T有约束条件,得是一个函数
  • 在实际使用的时候,使用infer推断返回值的类型并赋值给R
    • infer需要跟extends配合使用
  • 如果返回值类型推断不出来则会返回any

代码示例:

在线示例

interface User {
    name: string;
    age: number;
}

type Foo = () => User;

/**
 * 相当于:
 * type T = User;
 */
type T = ReturnType<Foo>;

const user: T = {
    name: '金小钗',
    age: 233,
}

ConstructorParameters(使用构造函数形参创建元组)

ConstructorParameters用于推断一个类的构造函数的形参类型,然后组合成一个有有名称的元组类型。 ​

源代码:

/**
 * Obtain the parameters of a constructor function type in a tuple
 */
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;
  • 首先T有约束条件,得有一个构造函数
  • 在实际使用的时候,使用infer推断参数的类型并赋值给P
    • infer需要跟extends配合使用
  • 返回的P类型是个有名称的元组

代码示例:

在线示例

// interface User {
//     new(): User;
//     name: string;
//     age: number;
// }
class User {
    private name: string;
    private age: number;

    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
}

// type T = ConstructorParameters<User>;
type T = ConstructorParameters<typeof User>;

const user: T = ['金小钗', 18];

很多知识我也还在学习中,更多详细信息请看下其他文章

InstanceType(获取构造函数返回值类型)

InstanceType可以用来获取一个类的构造函数的返回值类型。 ​

源代码:

/**
 * Obtain the return type of a constructor function type
 */
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;
  • 首先T有约束条件,得是一个构造函数
  • 在实际使用的时候,使用infer推断返回值的类型并赋值给R
    • infer需要跟extends配合使用
  • 如果返回值类型推断不出来则会返回any

代码示例:

在线示例

interface UserConstrutor {
    new(): User;
}
interface User {
    name: string;
    age: number;
}

/**
 * 相当于:
 * type T1 = User;
 */
type T1 = InstanceType<UserConstrutor>;

const user: T1 = {
    name: '金小钗',
    age: 233,
};



type T2 = InstanceType<ErrorConstructor>;

const error: T2 = {
    name: 'err',
    message: '错误',
}

ThisType(绑定上下文this)

ThisType是用在字面量对象中的,可以给其中定义的函数绑定上下文对象this。 ​

源码:

/**
 * Marker for contextual 'this' type
 */
interface ThisType<T> { }
  • 使用时需要开启编译配置noImplicitThis: true,否则使用this时没有智能提示功能

ThisType的实现就是个空的接口,只有在字面量对象类型中可以起到标示作用,否则直接使用也不会返回什么新的类型。

type T1 = ThisType<string>;
const a: T1 = '123';
const b: T1 = 1;
const c: T1 = { name: '金小钗' };

在上面代码中,虽然不会报错,但是变量使用起来就跟any类型一样。

代码示例:

在线示例 该代码来自官网

type ObjectDescriptor<D, M> = {
  data?: D;
  // this 的类型为联合类型,就是 data 与 methods 对象
  methods?: M & ThisType<D & M>; // Type of 'this' in methods is D & M
};

function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
  const data: object = desc.data || {};
  const methods: object = desc.methods || {};
  return { ...data, ...methods } as D & M;
}

const obj = makeObject({
  data: { x: 1, y: 2 },
  methods: {
    moveBy(dx: number, dy: number) {
      // 这里的 this 是有类型的
      this.x += dx; // Strongly typed this
      this.y += dy; // Strongly typed this
    },
  },
});

obj.x = 10;
obj.y = 20;
obj.moveBy(5, 5);
  • makeObject函数中,使用ObjectDescriptor限定参数的类型
    • DM用来推断实际的传入数据的类型
    • 在属性methods的定义中,使用了ThisType来标识了的函数中this的类型,这样就可以确保this是有明确的类型的

所以直接在makeObject函数中使用字面量的方式定义desc对象时,就会有类型限制和智能代码提示了。

this的类型:

image.png

代码提示:

image.png

内置字符串操作类型

主要是针对内容为英文字母的操作

Uppercase(转换为大写)

Uppercase可以将字符串类型转换为大写的。 ​

源码:

/**
 * Convert string literal type to uppercase
 */
type Uppercase<S extends string> = intrinsic;

intrinsic代表功能由TS内部实现。 ​

示例代码:

在线示例

/**
 * 相当于:
 * type T1 = 'ABC';
 */
type T1 = Uppercase<'abc'>

const str: T1 = 'ABC';

Lowercase(转换为小写)

Lowercase可以将字符串类型转换为小写的。 ​

源码:

/**
 * Convert string literal type to lowercase
 */
type Lowercase<S extends string> = intrinsic;

intrinsic代表功能由TS内部实现。 ​

示例代码:

在线示例

/**
 * 相当于:
 * type T1 = 'abc';
 */
type T1 = Lowercase<'ABC'>

const str: T1 = 'abc';

Capitalize(首字母转换为大写)

Capitalize可以将字符串类型的首字母转换成大写的。 ​

源码:

/**
 * Convert first character of string literal type to uppercase
 */  
type Capitalize<S extends string> = intrinsic;

intrinsic代表功能由TS内部实现。 ​

示例代码:

在线示例

/**
 * 相当于:
 * type T1 = 'Hello world';
 */
type T1 = Capitalize<'hello world'>

const str: T1 = 'Hello world';

Uncapitalize(首字母转换为小写)

Capitalize可以将字符串类型的首字母转换成小写的。 ​

源码:

/**
 * Convert first character of string literal type to lowercase
 */
type Uncapitalize<S extends string> = intrinsic;

intrinsic代表功能由TS内部实现。 ​

示例代码:

在线示例

/**
 * 相当于:
 * type T1 = 'hello World';
 */
type T1 = Uncapitalize<'Hello World'>

const str: T1 = 'hello World';