TypeScript Version: 2.2.2
Code
type Eg = { foo: string, bar: number }
type VariantRec<T> = {[K in keyof T]: { type: K, value: T[K] }}
type Alpha1 = VariantRec<Eg>[keyof Eg]
type VariantType<T> = VariantRec<T>[keyof T]
type Alpha2 = VariantType<Eg>
const assignable12: Alpha2 = null as Alpha1
const assignable21: Alpha1 = null as Alpha2
Expected behavior:
Types Alpha1 and Alpha2 should be the identical.
Actual behavior:
Alpha2 incorrectly becomes: { type: 'foo' | 'bar', value: string | number }
It should be: { type: 'foo', value: string } | { type: 'bar', value: number }
Interesting. I'd posted a similar issue at #16244.
Hey, we found a solution for mine by separating the steps using generic defaults; still kinda feels like a bug, but I think a workaround like that may solve your case too! 馃槂
@tycho01 Awesome, thanks! That appears to work 馃樃 Here's an updated playground.
Coming over from #16244, I just ran into another one super similar to yours, though here it doesn't seem fixable by defaults:
type Inc = [1, 2, 3, 4, 5];
type ObjectHasKey<O extends {}, K extends string> = ({[K in keyof O]: '1' } & { [k: string]: '0' })[K];
type Length<R extends {}, I extends number = 0> = { 1: Length<R, Inc[I]>, 0: I }[ObjectHasKey<R, I>];
type TestLenA = Length<{ 0: 'a', 1: 'b' }>;
// ^ ok, 2
type Wrap<O> = Length<O>;
// type Wrap<O, Len extends Length<O> = Length<O>> = Len;
// ^ old work-around, same result here
type TestLenB = Wrap<{ 0: 'a', 1: 'b' }>;
// ^ 0 :(
With the wrap wording I'm a bit reminded of #10247, though that concerned wrapping generic functions, while this is wrapping a generic type. Unfortunately, while in that other case one could observe the degenerating generics in the transformed output function, over here the inner workings feel somewhat opaque...
seems like a duplicate of https://github.com/Microsoft/TypeScript/issues/15756
Fixed by #18042.
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.
Most helpful comment
Hey, we found a solution for mine by separating the steps using generic defaults; still kinda feels like a bug, but I think a workaround like that may solve your case too! 馃槂