Typescript 的 DeepExclude 类型

dom*_*nik 0 typescript

我想Exclude在 Typescript 中有一个递归版本的类型。

排除从类型联合中删除一个类型。我想要一个版本,它也从任何嵌套对象和数组中删除类型。

例如

type O = DeepExclude<{foo: number | {bar: number}}, {bar: number}>;
Run Code Online (Sandbox Code Playgroud)

应该

type O = {
  foo: number;
}
Run Code Online (Sandbox Code Playgroud)

另一个例子:

type O = MappedExclude<[number | {foo: {bar: number} | number}], {bar: number}>;
Run Code Online (Sandbox Code Playgroud)

应该

type O = [number | {foo: number}]
Run Code Online (Sandbox Code Playgroud)

jca*_*alz 5

我会这样定义DeepExclude

type DeepExclude<T, U> =
  T extends U ? never :
  T extends object ? {
    [K in keyof T]: DeepExclude<T[K], U>
  } : T;
Run Code Online (Sandbox Code Playgroud)

第一部分和正常Exclude<T, U>定义一样

// type Exclude<T, U> = T extends U ? never : T;
Run Code Online (Sandbox Code Playgroud)

它删除了T可分配给 的任何联合部分U。任何剩余的T原语(不是object)都按原样返回,也好像它只是Exclude<T, U>. 然而,对于任何剩余的部分Tobjects,我们向下递归到它的属性并DeepExclude在这些属性上做 a 。

让我们看看它是否适用于您的用例:

type O = DeepExclude<{ foo: number | { bar: number } }, { bar: number }>;
/* type O = { foo: number; } */

type P = DeepExclude<[number | { foo: { bar: number } | number }], { bar: number }>;
/* type P = [number | {
    foo: number;
}] */
Run Code Online (Sandbox Code Playgroud)

是的,看起来不错。很可能存在无法按您期望的方式工作的边缘情况,因此请小心并进行大量测试。

Playground 链接到代码