Mic*_*urz 5 generics union discriminated-union typescript
我有一个受歧视的工会,例如:
type Union = { a: "foo", b: string, c: number } | {a: "bar", b: boolean }
Run Code Online (Sandbox Code Playgroud)
我需要派生一个包含所有潜在属性的类型,分配有可能在 的任何成员上找到的类型Union,即使仅在某些成员上定义 - 在我的示例中:
type CollapsedUnion = {
a: "foo" | "bar",
b: string | boolean,
c: number | undefined
}
Run Code Online (Sandbox Code Playgroud)
我怎样才能制作一个派生出这种折叠联合的泛型?
我需要一个支持任何大小联合的泛型。
通过使用 native OmitUtility可以作为副产品实现类似的行为,但不幸的是,它遗漏了每个联合成员上不存在的属性(不将它们计入 asundefined或 via ?)。
Aro*_*ron 10
我找到了两种 方法!
编辑:这是一个具有两个单独类型参数的解决方案。请参阅下面的带有单个联合类型参数的解决方案。
\n// The source types\ntype A = { a: "foo", b: string, c: number }\ntype B = { a: "bar", b: boolean }\n\n// This utility lets T be indexed by any (string) key\ntype Indexify<T> = T & { [str: string]: undefined; }\n\n// Where the magic happens \xe2\x9c\xa8\ntype AllFields<T, R> = { [K in keyof (T & R) & string]: Indexify<T | R>[K] }\n\ntype Result = AllFields<A, B>\n/**\n * \n * type Result = {\n * a: "foo" | "bar";\n * b: string | boolean;\n * c: number | undefined;\n * }\n */\nRun Code Online (Sandbox Code Playgroud)\n怎么运行的
\nAllFields是映射类型。映射类型的“key”部分
[K in keyof (T & R) & string]\nRun Code Online (Sandbox Code Playgroud)\n意味着K扩展 union 的键,这意味着它将是 in或 inT & R的所有键的并集。这是第一步。它确保我们使用所有必需的键来创建一个对象。TR
是& string必需的,因为它指定K也必须是字符串。无论如何,情况几乎总是如此,因为 JS 中的所有对象键都是字符串(偶数) \xe2\x80\x93 除了符号之外,但无论如何,这些都是不同的鱼。
类型表达式
\nIndexify<T | R>\nRun Code Online (Sandbox Code Playgroud)\nT返回and的联合类型,但添加了字符串索引。这意味着,如果我们尝试对它进行索引,即使或 之一不存在,RTS 也不会抛出错误。KKTR
最后
\nIndexify<T | R>[K]\nRun Code Online (Sandbox Code Playgroud)\n意味着我们正在为这个 union-with-undefineds-for-string-indexes 建立索引K。如果是、或两者K的键,则将产生该键的值类型。TR
否则,它将回退到[string]: undefined索引并导致值未定义。
编辑:单个通用参数的解决方案
\n您指定实际上并不希望它适用于两个类型参数,而是适用于现有的联合类型,无论联合中有多少个成员。
\n这需要血、汗和泪水,但我已经做到了。
\n// Magic as far as I\'m concerned.\n// Taken from /sf/answers/3526270051/\ntype UnionToIntersection<U> =\n (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never\n\n// This utility lets T be indexed by any key\ntype Indexify<T> = T & { [str: string]: undefined; }\n\n// To make a type where all values are undefined, so that in AllUnionKeys<T>\n// TS doesn\'t remove the keys whose values are incompatible, e.g. string & number\ntype UndefinedVals<T> = { [K in keyof T]: undefined }\n\n// This returns a union of all keys present across all members of the union T\ntype AllUnionKeys<T> = keyof UnionToIntersection<UndefinedVals<T>>\n\n// Where the (rest of the) magic happens \xe2\x9c\xa8\ntype AllFields<T> = { [K in AllUnionKeys<T> & string]: Indexify<T>[K] }\n\n\n// The source types\ntype A = { a: "foo", b: string, c: number }\ntype B = { a: "bar", b: boolean; }\n\ntype Union = A | B\n\ntype Result = AllFields<Union>\n/**\n * \n * type Result = {\n * a: "foo" | "bar";\n * b: string | boolean;\n * c: number | undefined;\n * }\n */\nRun Code Online (Sandbox Code Playgroud)\n我UnionToIntersection从@jcalz 的精彩回答中得到了答案。我试图理解它,但无法理解。无论如何,我们可以将其视为一个将并集类型转换为交集类型的魔术盒。这就是我们获得想要的结果所需要的一切。
| 归档时间: |
|
| 查看次数: |
150 次 |
| 最近记录: |