我在tsc 3.2.2中看到混乱的行为。我有两种类型,但我希望它们是等效的(根据VSCode intellisense-是否有更好的检查方法?)。
首先,我有一个用type
键来区分的区分联合。我的想法是,我将通过判别式查找适当的类型,然后删除type
键以获取有效负载类型:
interface A { type: 'a', x: number }
interface B { type: 'b', y: string }
type Request = A | B
我有一些辅助类型。 Omit
来自TS文档,Discriminate
接受一个有区别的联合,该区别键以及该键的值以在查找中使用,并从联合中生成匹配类型:
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>
type Discriminate<T, U extends keyof T, V extends T[U]> =
T extends Record<U, V> ? T : never
现在,我定义一个帮助程序,以通过Request
键来获取type
变体:
type RequestType<T extends Request['type']> = Discriminate<Request, 'type', T>
type A2 = RequestType<'a'> // Equals A, good so far
现在,我添加一个助手以通过Request
键获取type
负载类型:
type RequestPayload<T extends Request['type']> = Omit<RequestType<T>, 'type'>
type APayload = RequestPayload<'a'> // {} - That's not right!
但是,如果我更直接地计算有效载荷类型,它将起作用:
type APayload2 = Omit<RequestType<'a'>, 'type'> // { x: number } - Correct
APayload
和APayload2
有什么区别?这可能是一个错误吗?我认为我很可能遗漏了一些东西。它们似乎应该是相同的。
答案 0 :(得分:4)
如果您查看RequestType
定义的工具提示,则实际上是联合类型:
type RequestType<T extends "a" | "b"> = Discriminate<A, "type", T> | Discriminate<B, "type", T>
在其上使用Omit
时,keyof
中的Omit
仅遍历联合的所有成员中存在的键,即Omit
只会看到type
键,而看不到其他任何键,而当您忽略它时,结果类型为空。
您需要使用Omit
的特殊版本来修复它。您需要UnionOmit
使“ distributes” Omit
超过工会成员,然后立即再次将工会重新组装起来:
type UnionOmit<T, K> = T extends {} ? Pick<T, Exclude<keyof T, K>> : never;
type RequestPayload<T extends Request['type']> = UnionOmit<RequestType<T>, 'type'>
type APayload = RequestPayload<'a'> // {x: number}