我想写一个递归地省略字段的类型实用程序,你可以这样命名和使用
我尝试过使用Map类型+条件类型来实现,但我坚持这样一种情况,即所有必需字段都正确键入(因此字段从嵌套类型中消失),但可选字段在这种方法中被忽略。
// This is for one function that removes recursively __typename field
// that Appolo client adds
type Deapolify<T extends { __typename: string }> = Omit<
{ [P in keyof T]: T[P] extends { __typename: string } ? Deapolify<T[P]> : T[P] },
'__typename'
>
// Or more generic attempt
type OmitRecursively<T extends any, K extends keyof T> = Omit<
{ [P in keyof T]: T[P] extends any ? Omit<T[P], K> : never },
K
>
预期行为将是根,并且所有类型中包含应递归省略的键的嵌套键都将被省略。
type A = {
keyToKeep: string
keyToOmit: string
nested: {
keyToKeep: string
keyToOmit: string
}
nestedOptional?: {
keyToKeep: string
keyToOmit: string
}
}
type Result = OmitRecursively<A, 'keyToOmit'>
type Expected = {
keyToKeep: string
nested: {
keyToKeep: string
}
nestedOptional?: {
keyToKeep: string
}
}
Expected === Result
2条答案
按热度按时间rxztt3cl1#
你不能递归地调用
OmitRecursevly
,而且我也只会在属性类型是一个对象时递归地应用省略符,否则它应该基本上可以工作:Playground链接
Omit
帮助器类型的添加。对于旧版本,只需定义"忽略"。Id
主要用于装饰(它强制编译器在工具提示中展开Pick
),可以删除,它有时会在某些核心情况下导致问题。strictNullChecks
,因为属性的类型是type | undefined
。我编辑了代码以在联合体上分发。条件类型OmitDistributive
用于其分发行为(我们使用它的原因不是条件)。这意味着OmitRecursively
将应用于联合体的每个成员。默认情况下
Omit
类型在联合体上不起作用。Omit
将联合体视为一个整体,不会从联合体的每个成员中提取属性。这主要是由于keyof
只返回联合体的公共属性(因此keyof undefined | { a: number }
实际上是never
,因为没有公共属性)。幸运的是,有一种方法可以使用条件类型钻取联合。条件类型将分布在裸类型参数上(关于docs的解释,请参见此处)。对于
OmitDistributive
,我们并不真正关心条件(这就是为什么我们使用T extends any
)我们只关心如果我们使用条件类型,T
将依次是联合体中的每个成员。这意味着这些类型是等效的:
pkwftd7m2#
我写了一篇关于这个主题的扩展文章:Writing a Recursive Utility Type in TypeScript.
首先,代码:
......还有操场链接
所有这些都需要涵盖以下情况:
这在很大程度上等同于另一个答案,但在我看来,它有一个稍微干净的方法。