I am seeing confusing behavior in tsc 3.2.2. I have two types that I expect to be equivalent but are not (according to VSCode intellisense - is there a better way to check?).
First, I have a discriminated union discriminated by a type key. The idea is that I will look up the proper type via the discriminant and then remove the type key to get the payload type:
interface A { type: 'a', x: number }
interface B { type: 'b', y: string }
type Request = A | B
I have some helper types. Omit comes from the TS docs, and Discriminate takes a discrimated union, the discriminant key, and the value for that key to use in the lookup and produces the matching type from the union:
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
Now I define a helper to get the Request variant by type key:
type RequestType<T extends Request['type']> = Discriminate<Request, 'type', T>
type A2 = RequestType<'a'> // Equals A, good so far
Now I add a helper to get the Request payload type by type key:
type RequestPayload<T extends Request['type']> = Omit<RequestType<T>, 'type'>
type APayload = RequestPayload<'a'> // {} - That's not right!
However, if I calculate the payload type more directly, it works:
type APayload2 = Omit<RequestType<'a'>, 'type'> // { x: number } - Correct
What is the difference between APayload and APayload2? Is this maybe a bug? I think it's far more likely that I'm missing something. They seem like they should be identical.