这里的工具类是 【utility-types】的源码。

Object 操作

IfEquals(是否相等)

用于判断两个类型是否相等。

  1. export type IfEquals<X, Y, A = X, B = never> = (<T>() => T extends X ? 1 : 2) extends <
  2. T
  3. >() => T extends Y ? 1 : 2
  4. ? A
  5. : B

如果你了解一些 TS 的话可能会想到,判断两个类型是否相同不是直接使用双向 extends 就可以了吗,这个是什么玩意?
我想你说的双向 extends 方式是这样的。

type Same<X, Y> = X extends Y ? (Y extends X ? true : false) : false

对于上面 Same 类型函数这种写法,其实是有缺陷的,它没有办法推断两个类型是否绝对相同,比如说相同结构但带有不同属性修饰符的对象类型。

type X = {
  name: string
  age: number
}
type Y = {
  readonly name: string
  age: number
}

上面这两个类型 Same 类型函数就无法推断,这种情况下就必须要使用IfEquals类型函数了。

type SameResult = Same<X, Y> //true
type IfEqualsResult = IfEquals<X, Y> //never

WriteableKeys(可写的key)

用于获取对象类型中所有可写的 key。
源码:

export type WriteableKeys<T extends object> = {
  [P in keyof T]-?: IfEquals<
    { [Q in P]: T[P] },
    { -readonly [Q in P]: T[P] },
    P
  >
}[keyof T];

示例:

type Props = { readonly foo: string; bar: number }

type WriteableKeysResult = WriteableKeys<Props> // "bar"

ReadonlyKeys(只读的key)

用于获取对象中所有 readonly 的key。
源码:

export type ReadonlyKeys<T extends object> = {
  [P in keyof T]-?: IfEquals<
    { [Q in P]: T[P] },
    { -readonly [Q in P]: T[P] },
    never,
    P
  >
}[keyof T]

示例:

type Props = { readonly foo: string; bar: number }

type ReadonlyKeysResult = ReadonlyKeys<Props> // "foo"

RequiredKeys(必选的key)

用于获取对象中所有必选的key。
源码:

export type RequiredKeys<T extends object> = {
  [P in keyof T]-?: {} extends Pick<T, P> ? never : P
}[keyof T]

示例:

interface Props {
  age: number;
  name?: string;
}
type Demo = RequiredKeys<Props>  // type Demo = 'age'

OptionalKeys(可选的key)

用于获取对象中所有可选的key。
源码:

export type OptionalKeys<T extends object> = {
  [P in keyof T]-?: {} extends Pick<T, P> ? P : never
}[keyof T]

示例:

interface Props {
  age: number;
  name?: string;
}
type Demo = OptionalKeys<Props>   // type Demo = 'name'

Optional(部分可选)

接收两个泛型参数,T和K,K是T所有key的子集,并将T中兼容的K属性转换为可选。
源码:

export type Optional<
  T extends object,
  K extends keyof T = keyof T,
  I = Omit<T, K> & Partial<Pick<T, K>>
> = Pick<I, keyof I>

示例:

type Props = {
  name: string;
  age: number;
}
type Demo = Optional<Props, 'name'>
// type Demo = {name?: string; age: number}

PickByValue(根据value过滤)

根据value的类型,来过滤对象的key。
源码:

export type PickByValue<T, K> = Pick<
  T,
  {
    [P in keyof T]-?: T[P] extends K ? P : never
  }[keyof T]
>

示例:

interface Props {
  age: number;
  name?: string;
  color: string;
}
type Demo = PickByValue<Props, string> // type Demo = { color: string }

上面的代码中,只过滤了必选的。

PickByValueExact

嗯,是 PickByValue 的严格版。

export type PickByValueExact<T, K> = Pick<
  T,
  {
    [P in keyof T]-?: IfEquals<[K], [T[P]], P>
  }[keyof T]
>

OmitByValue(反向PickByValue)

反向根据value过滤。
源码:

export type OmitByValue<T, U> = Pick<
  T,
  {
    [P in keyof T]: T[P] extends U ? never : P
  }[keyof T]
>

示例:

interface Props {
  age: number;
  color: string;
}

type Demo = OmitByValue<Props, number> 
// type Demo = { color: string }

Instersection(交集)

获取两个对象中的交集。
源码:

export type Intersection<T extends object, U extends object> = Pick<
  T,
  Extract<keyof T, keyof U> & Extract<keyof U, keyof T>
>

示例:

type Props1 = {
  name: string
  age: number
  visible: boolean
  sex: string | number
}

type Props2 = {
  age: number;
  color: string;
  type: boolean;
}

type Demo = Intersection<Props1, Props2>  // type Demo = {age: number}

Diff(差集)

同 Instersection 相反。

export type Diff<T extends object, U extends object> = Pick<
  T,
  Exclude<keyof T, keyof U>
>

示例:

type Props1 = {
  name: string
  age: number
  visible: boolean
  sex: string | number
}

type Props2 = {
  age: number;
}

type Demo = Diff<Props1, Props2>  
// type Demo = {name: string; visible: boolean; sex: string | number;}

Overwrite(重写)

接收两个参数,A和B。B的属性类型会覆盖A的属性类型。
源码:

export type Overwrite<
  T extends object,
  U extends Object,
  I = Diff<T, U> & Intersection<U, T>
> = Pick<I, keyof I>

示例:

type Props = {
  name: string;
  age: number;
}

type Props2 = {
  age: string;
}
type Demo = Overwrite<Props, Props2>
// type Demo = {name: string; age: string}

Assign(强制重写)

比 Overwrite 更强大一些,当B中有A不存在的属性时,会添加到A对象中。
源码:

export type Assign<
  T extends object,
  U extends object,
  I = Diff<T, U> & Intersection<U, T> & Diff<U, T>
> = Pick<I, keyof I>

示例:

type Props = {
  name: string;
  age: number;
}

type Props2 = {
  color: string;
}

type Demo = Assign<Props, Props2>
// type Demo = {name: string; age: number; color: string;}

ValuesType

接收一个泛型参数,返回值的联合类型。如果是数组的话,返回其中的子元素。
源码:

export type ValuesType<
  T extends Array<any> | ReadonlyArray<any> | ArrayLike<any> | object
> = T extends Array<any> | ReadonlyArray<any> | ArrayLike<any>
  ? T[number]
  : T extends object
  ? T[keyof T]
  : never

示例:


type Props = {
  name: string;
  age: number;
}

type Demo = ValuesType<Props>
// type Demo = string | number;

type Props2 = Array<{
  name: string;
  age: number;
}>

type Demo2 = ValuesType<Props2>
// type Demo2 = {name: string; age: number;}

Unionize(重组联合)

接收一个对象,返回一个转为单独key对象的联合类型。
源码:

export type Unionize<T extends object> = {
  [P in keyof T]: { [Q in P]: T[P] }
}[keyof T]

示例:

type Props = { name: string; age: number; visible: boolean }
type UnionizeResult = Unionize<Props>
// {
//     name: string;
// } | {
//     age: number;
// } | {
//     visible: boolean;
// }

Mutable (转换只读)

将对象中所有只读的属性转换为非只读类型。
源码:

export type Mutable<T> = { -readonly [P in keyof T]: T[P] };

示例:

type Demo = Mutable<{readonly age: number}>
// type Demo = {age: number}

MutableKeys (只读的key)

用于获取对象中所有非只读属性的key。
源码:

export type MutableKeys<T extends object> = {
  [P in keyof T]-?: IfEquals<
    { [Q in P]: T[P] },
    { -readonly [Q in P]: T[P] },
    P
  >;
}[keyof T];

示例:

type Demo = MutableKeys<{age: number, readonly color: string, name: string}>
// type Demo = 'age' | 'name';

ArgumentsRequired(参数必选)

用于将泛型的参数都转换为必选。
源码:

export type ArgumentsRequired<
  T extends object,
  K extends keyof T = keyof T,
  I = Omit<T, K> & Required<Pick<T, K>>
> = Pick<I, keyof I>

示例:

type Props = {
  name?: string;
  age?: number;
}

type Demo = ArgumentsRequired<Props>
// type Demo = {name: string; age: number;}

其他操作

Unionize(转联合)

用于将一个对象转换为联合类型。
源码:

export type Unionize<T extends object> = {
  [P in keyof T]: { [Q in P]: T[P] }
}[keyof T]

示例:

type Props = { name: string; age: number; visible: boolean };

// Expect: { name: string; } | { age: number; } | { visible: boolean; }
type UnionizedType = Unionize<Props>;

ReturnType(返回类型)

获取函数类型的返回类型。

interface Props{
  age: number;
  name: string;
}
type getUrl = (url: string) => Props;
type Demo = ReturnType<getUrl> // type Demo = Props;

InstanceType

获取构造函数函数类型的返回类型,有些类似 ConstructorParameters。

type E = InstanceType<ErrorConstructor>; // type F = Error
type F = InstanceType<FunctionConstructor>; // type F = Function

Parameters(函数参数)

用于获得当前函数参数类型,组成的数组。

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[]

type getUrl = (url: string, options: IProps) => string;
type Demo = Parameters<getUrl>;
// type Demo = [url: string, options: IProps];

PromiseType

用于返回Promise泛型的类型。
源码:

export type PromiseType<T extends Promise<unknown>> = T extends Promise<infer V>
  ? V
  : never

示例:

type PromiseTypeResult = PromiseType<Promise<string>>
// string

TupleToUnion(元组转联合)

将一个元组(数组)类型转换为一个联合类型。
源码:

export type TupleToUnion<T extends any[]> = T extends Array<infer U> ? U : never

示例:

type Demo = TupleToUnion<[string, number]>
// type Demo = string | number;

UnionToIntersection(联合转交集)

用于将一个联合类型转换为一个交叉类型。
源码:

export type UnionToIntersection<T> = (T extends any
? (arg: T) => void
: never) extends (arg: infer V) => void
  ? V
  : never

示例:

type Demo = UnionToIntersection<
  { name: string } | { age: number } | { visible: boolean }
>
// type Demo = { name: string } & { age: number } & { visible: boolean }
// 又或者  { name: string; age: number; visible: boolean }