在通用类型后面

时间:2019-01-14 17:26:33

标签: typescript

我在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

APayloadAPayload2有什么区别?这可能是一个错误吗?我认为我很可能遗漏了一些东西。它们似乎应该是相同的。

1 个答案:

答案 0 :(得分:4)

如果您查看RequestType定义的工具提示,则实际上是联合类型:

type RequestType<T extends "a" | "b"> = Discriminate<A, "type", T> | Discriminate<B, "type", T>

在其上使用Omit时,keyof中的Omit仅遍历联合的所有成员中存在的键,即Omit只会看到type键,而看不到其他任何键,而当您忽略它时,结果类型为空。

您需要使用Omit的特殊版本来修复它。您需要UnionOmit使“ distributesOmit超过工会成员,然后立即再次将工会重新组装起来:

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}