Typescript内置工具类型(二)

168 阅读3分钟

调试环境:TypeScript Playground

1. Awaited

作用: 获取Promise中的类型(如await、then方法返回的被Promise包裹的数据的类型)。适合处理异步操作并确保解析值的类型安全。

使用

type A = Awaited<Promise<string>>; // string
type B = Awaited<Promise<Promise<number>>>; // number

// 假如这是一个第三方库,User没有导出,fetchUser函数导出了
interface User {
	name: string
	age: number
}
export async function fetchUser(): Promise<User> {
	const data = await fetch('https://www.example.com/user').then(res => {
		return res.json()
	})
	return data
}

// 我们开发中在获取到了User类型
type UserFetch = Awaited<ReturnType<typeof fetchUser>>

async function getUserInfo() {
  let user: UserFetch = { name: 'x', age: 30 }
  return user
}

源码实现

 * Recursively unwraps the "awaited type" of a type. Non-promise "thenables" should resolve to `never`. This emulates the behavior of `await`.
 */
type Awaited<T> = T extends null | undefined ? T : // special case for `null | undefined` when not in `--strictNullChecks` mode
    T extends object & { then(onfulfilled: infer F, ...args: infer _): any; } ? // `await` only unwraps object types with a callable `then`. Non-object types are not unwrapped
        F extends ((value: infer V, ...args: infer _) => any) ? // if the argument to `then` is callable, extracts the first argument
            Awaited<V> : // recursively unwrap the value
        never : // the argument to `then` was not callable
    T; // non-object or non-thenable

2. ConstructorParameters

作用: 接受一个具有构造函数的类型, 将构造函数的参数处理成一个元组类型。

使用

class Test { constructor(a: number, b: string) {}}
type T1 = ConstructorParameters<typeof Test>; //  [a: number, b: string]
                                
type T2 = ConstructorParameters<new (x: string, y: number) => any> // [x: string, y: number]

源码实现

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

3. InstanceType

作用: 获取构造函数类型的返回类型(构造函数返回什么什么类型,InstanceType获取的就是什么类型)。

使用

class Person {
    constructor(public name: string) {}
}
type PersonInstance = InstanceType<typeof Person>
const person: PersonInstance = new Person('Alice')

interface User {
	new (name: string): Object
}
type UserInstance = InstanceType<User> // Object

源码实现

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

4. ThisType

作用: 控制字面量对象中this所表示的类型。 只在--noImplicitThis下有用

使用

// 正常情况推导出来的this
type Point = {
    x: number;
    y: number;
    moveBy(dx: number, dy: number): void;
}

let p: Point = {
    x: 10,
    y: 20,
    moveBy(dx, dy) {
        this.x += dx;  // this has type Point
        this.y += dy;  // this has type Point
    }
}

// 使用ThisType进行控制this
type Point = {
  x: number;
  y: number;
  moveBy(dx: number, dy: number): void;
}

let p: ThisType<{x: number}> &  Point = {
  x: 10,
  y: 20,
  moveBy(dx, dy) {
      this.x += dx;  // this has type Point
      this.y += dy;  // error ❗️类型“{ x: number; }”上不存在属性“y”。
  }
}

源码实现

interface ThisType<T> {}

扩展:

对象字面值方法中的表达式this的类型按照下面的方法进行确定:

  1. 如果方法具有显式声明的this参数,则this具有该参数的类型。
  2. 如果方法带了this参数,那么this就是这个。
  3. 如果对象字面量有ThisType<T>的上下文类型,则该类型为T。
  4. 如果不包含,那么就自动推导
  5. 否则,this就是any

5. ThisParameterType

作用: 提取函数类型的this参数的类型, 如果函数类型没有this参数, 返回unknown。

使用

function toHex(this: Number) {
  return this.toString(16);
}
 
function numberToString(n: ThisParameterType<typeof toHex>) {
  return toHex.apply(n);
}

源码实现

type ThisParameterType<T> = T extends (this: infer U, ...args: never) => any ? U : unknown;

6. OmitThisParameter

作用: 与ThisParameterType相反, 排除函数类型的this参数

使用

function toHex(this: Number) {
  return this.toString(16);
}
 
const fiveToHex: OmitThisParameter<typeof toHex> = toHex.bind(5);
 
console.log(fiveToHex());

源码实现

type OmitThisParameter<T> = unknown extends ThisParameterType<T> ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T;

7.NoInfer

作用: 阻止对所包含类型的推断。除了阻止推断之外,NoInfer<Type> 与 Type 相同。

使用

function createStreetLight<C extends string>(
    colors: C[],
    defaultColor?: NoInfer<C>,
) {
    // ...
}

createStreetLight(["red", "yellow", "green"], "red"); // OK
createStreetLight(["red", "yellow", "green"], "blue"); // Error

源码实现

type NoInfer<T> = intrinsic

8. Uppercase

作用: 将字符串中的每个字符转换为对应的大写。

使用

type Greeting = 'Hello, world'
type ShoutyGreeting = Uppercase<Greeting> // "HELLO, WORLD"

type ASCIICacheKey<Str extends string> = `ID-${Uppercase<Str>}`
type MainID = ASCIICacheKey<'my_app'> // "ID-MY_APP"

源码实现

type Uppercase<S extends string> = intrinsic;

9. Lowercase

作用: 将字符串中的每个字符转换为对应的小写。

使用

type Greeting = 'Hello, world'
type QuietGreeting = Lowercase<Greeting> //  "hello, world"

type ASCIICacheKey<Str extends string> = `id-${Lowercase<Str>}`
type MainID = ASCIICacheKey<'MY_APP'> // "id-my_app"

源码实现

type Lowercase<S extends string> = intrinsic;

10.Capitalize

作用: 将字符串中的第一个字符转换为大写字母。

11. Uncapitalize

作用: 将字符串中的第一个字符转换为小写字母。