Description
TypeScript Version: Version 3.6.0-dev.20190602
Search Terms: "generic return type"
(returns too many results, sorry)
Code
function copy<K extends string, J extends string, T extends Record<K, number>>(
o: T, s: K, t: J
): T & Record<J, number> {
return { ...o, [t]: o[s] };
}
const { b } = copy({ a: 2 }, 'a', 'b');
Expected behavior:
Code compiles with 3.4.x. It is unsound when explicitly specifying type params, but with implicit type params it lets me express the type of copy
.
Actual behavior:
With 3.5.1 compilation fails:
../../../../../../tmp/x.ts:4:5 - error TS2322: Type 'T & { [x: string]: T[K]; }' is not assignable to type 'T & Record<J, number>'.
Type 'T & { [x: string]: T[K]; }' is not assignable to type 'Record<J, number>'.
4 return { ...o, [t]: o[s] };
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Found 1 error.
Here's the thing: the new compiler is correct, the claimed type is unsound. I can specialize the call to copy
to make it unsound, e.g.
const { c }: Record<'c', number> = copy<'a', 'b' | 'c', Record<'a', number>>({ a: 2 }, 'a', 'b');
actually compiles with 3.4.5, and now c
is undefined
and 3.4.5 thinks it has type number
. 3.5.1 prevents that (yay!).
I would like a way to type copy
; I used to have an unsound type for it (but safe unless used with explicit type params), now I have no way to type it.
Related Issues:
Even found a suspect PR!