美文网首页
TypeScript工具类型集合

TypeScript工具类型集合

作者: YM雨蒙 | 来源:发表于2023-12-04 19:59 被阅读0次

辅助工具类型

  1. 对于交叉类型的结构,Flatten 能够将它展平为单层的对象结构
type Flatten<T> = { [K in keyof T]: T[K] };

属性修饰类型工具

  1. 深度可选参数
type DeepPartial<T extends object> = {
  [K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
  1. 深度必选参数
type DeepRequired<T extends object> = {
  [K in keyof T]-?: T[K] extends object ? DeepRequired<T[K]> : T[K];
};
  1. 深度只读参数
// 也可以记作 DeepImmutable
type DeepReadonly<T extends object> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};
  1. 深度可变参数
type DeepMutable<T extends object> = {
  -readonly [K in keyof T]: T[K] extends object ? DeepMutable<T[K]> : T[K];
};
  1. 从联合类型剔除 null | undefined
    • 在开启 --strictNullChecks 下才能正常工作。
type NonNullable<T> = T extends null | undefined ? never : T;

type DeepNonNullable<T extends object> = {
  [K in keyof T]: T[K] extends object
    ? DeepNonNullable<T[K]>
    : NonNullable<T[K]>;
};

基于部分属性修饰的类型工具

  • 拆分对象结构,那不就是内置工具类型一节中讲到的结构工具类型,即 Pick 与 Omit?
  • 三个属性的对象全部变为可选,那不就是属性修饰?岂不是可以直接用上面刚学到的递归属性修饰?
  • 组合两个对象类型,也就意味着得到一个同时符合这两个对象类型的新结构,那不就是交叉类型?
  1. 将一个对象的部分属性标记为可选
/**
 * T: 需要处理的对象类型
 * K: 需要标记为可选的属性, 必须为 T 内部的属性, 对象属性组成的字面量联合类型
 */
type MarkPropsAsOptional<
  T extends object,
  K extends keyof T = keyof T
> = Flatten<Partial<Pick<T, K>> & Omit<T, K>>;

type MarkPropsAsOptionalStruct = MarkPropsAsOptional<
  {
    foo: string;
    bar: number;
    baz: boolean;
  },
  "bar"
>;
  1. 将一个对象的部分属性标记为必须
type MarkPropsAsRequired<
  T extends object,
  K extends keyof T = keyof T
> = Flatten<Omit<T, K> & Required<Pick<T, K>>>;
  1. 将一个对象的部分属性标记为只读
type MarkPropsAsReadonly<
  T extends object,
  K extends keyof T = keyof T
> = Flatten<Omit<T, K> & Readonly<Pick<T, K>>>;
  1. 将一个对象的部分属性不只读(可变)
type MarkPropsAsMutable<
  T extends object,
  K extends keyof T = keyof T
> = Flatten<Omit<T, K> & Mutable<Pick<T, K>>>;
  1. 讲一个对象的部分属性剔除 null | undefined
type MarkPropsAsNonNullable<
  T extends object,
  K extends keyof T = keyof T
> = Flatten<Omit<T, K> & NonNullable<Pick<T, K>>>;

结构工具

  1. 基于期望的类型去拿到所有此类型的属性名, Pick 出所有函数类型的值
type FuncStruct = (...args: any[]) => any;

type FunctionKeys<T extends object> = {
  [K in keyof T]: T[K] extends FuncStruct ? K : never;
}[keyof T];
// 对上面的解释
type Tmp<T extends object> = {
  [K in keyof T]: T[K] extends FuncStruct ? K : never;
};

type Res = Tmp<{
  foo: () => void;
  bar: () => number;
  baz: number;
}>;

type ResEqual = {
  foo: 'foo';
  bar: 'bar';
  baz: never;
};
type WhatWeWillGet = Res[keyof Res]; // 'foo' | 'bar'

type WhatWillWeGetEqual1 = Res["foo" | "bar" | "baz"];
type WhatWillWeGetEqual2 = Res["foo"] | Res["bar"] | Res["baz"];
type WhatWillWeGetEqual3 = "foo" | "bar" | never;
  1. 基于键值类型查找属性, 将预期类型也作为泛型参数
// 我们预期查找的类型, 第二个参数
type ExpectedPropKeys<T extends object, valueType> = {
  [Key in keyof T]-?: T[Key] extends valueType ? Key : never;
}[keyof T];

type PickByValueType<T extends object, valueType> = Pick<
  T,
  ExpectedPropKeys<T, valueType>
>;

// {
//   foo: string;
// }
type PickResult1 = PickByValueType<{ foo: string; bar: number }, string>;

// {
//   foo: string;
//   bar: number;
// }
type PickResult2 = PickByValueType<
  { foo: string; bar: number; baz: boolean },
  string | number
>;
// OmitByValueType 也是类似的,我们只需要一个和 ExpectedPropKeys 作用相反的工具类型即可,比如来个 FilteredPropKeys,只需要调换条件类型语句结果的两端

type FilteredPropKeys<T extends object, ValueType> = {
  [Key in keyof T]-?: T[Key] extends ValueType ? never : Key;
}[keyof T];

type OmitByValueType<T extends object, ValueType> = Pick<
  T,
  FilteredPropKeys<T, ValueType>
>;

type OmitRes1 = OmitByValueType<{ foo: string; bar: number }, string>;
type OmitRes2 = OmitByValueType<
  { foo: string; bar: number; baz: boolean },
  string | number
>;

集合工具

// 一维
// 并集
type Concurrence<A, B> = A | B
// 交集
type Intersection<A, B> = A extends B ? A : never
// 差集
type Difference<A, B> = A extends B ? never : A
// 补集
type Complement<A, B extends A> = Difference<A, B>
  1. 属性名并集
// 实现对象属性名的版本
type PlainObjectType = Record<string, any>;

// 属性名并集
type ObjectKeysConcurrence<
  T extends PlainObjectType,
  U extends PlainObjectType
> = keyof T | keyof U;
  1. 属性名交集
// 属性名交集
type ObjectKeysIntersection<
  T extends PlainObjectType,
  U extends PlainObjectType
> = Intersection<keyof T, keyof U>;
  1. 属性名差集
// 属性名差集
export type ObjectKeysDifference<
  T extends PlainObjectType,
  U extends PlainObjectType
> = Difference<keyof T, keyof U>;
  1. 属性名补集
// 属性名补集
export type ObjectKeysComplement<
  T extends U,
  U extends PlainObjectType
> = Complement<keyof T, keyof U>;
  1. 提取首个参数类型
type FunctionType = (...args: any) => any;

type FirstParameter<T extends FunctionType> = T extends (
  arg: infer P,
  ...args: any
) => any
  ? P
  : never;
  1. 提取最后一个参数
type FunctionType = (...args: any) => any;
type LastParameter<T extends FunctionType> = T extends (arg: infer P) => any
  ? P
  : T extends (...args: infer R) => any
  ? R extends [...any, infer Q]
    ? Q
    : never
  : never;

type FuncFoo = (arg: number) => void;
type FuncBar = (...args: string[]) => void;
type FuncBaz = (arg1: string, arg2: boolean) => void;

type FooLastParameter = LastParameter<FuncFoo>; // number
type BarLastParameter = LastParameter<FuncBar>; // string
type BazLastParameter = LastParameter<FuncBaz>; // boolean
  1. 提取 Promise 内部值类型的工具类型 PromiseValue
// 首先提取到 then 方法中的函数类型,再通过这个函数类型的首个参数来提取出实际的值。


type Awaited<T> = T extends null | undefined
  ? T
  : T extends object & { then(onfulfilled: infer F): any }
  ? F extends (value: infer V, ...args: any) => any
    ? Awaited<V>
    : never
  : T;

相关文章

网友评论

      本文标题:TypeScript工具类型集合

      本文链接:https://www.haomeiwen.com/subject/trkutdtx.html