-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot type a function that copies a property in an object #31725
Comments
The unsoundness actually extends a bit further than you think.
This doesn't mean what you think it means. See #31661 (comment), in particular:
In other words the index signature doesn't mean that "it has every possible property"--which is logistically impossible--but rather that "it can have any possible property"; for the purposes of structural subtyping these are not equivalent. Thus: Because |
Thanks, that makes sense! My question remains: what is the type of a function |
Can you specify a few more examples of valid and invalid calls to |
You're right, I under-specified the desired type. I would like to type this JavaScript function: function copy(o, s, t) {
return { ...o, [t]: o[s] };
} where Desired types: copy({ a: 'one', b: 2 }, 'b', 'c'); // Returns { a: 'one', b: 2, c: 2}, type { a: string, b: number, c: number }
const b: B = makeB();
copy({ a: 1, b: makeB() }, 'b', 'c'); // Returns value of type { a: number, b: B, c: B }
copy({ a: 'one' }, 'b', 'c'); // Does not compile, `o` has no property `b`.
const k: string = 'b';
copy({ a: 'one', b: 1 }, k, 'c'); // Don't care if it compiles (with less useful type) or fails to compile. Hope this makes better sense! |
The signature you want is: function copy<T, K extends keyof T, J extends string>(obj: T, srcKey: K, dstKey: J): T & Record<J, T[K]> The implementation is just going to need a type assertion somewhere; this is inherent in the fact that you can't really be sure that you're not self-overwriting in a broken way inside the function body |
Thanks, that works -- and I understand why we need a type assertion! |
TypeScript Version: Version 3.6.0-dev.20190602
Search Terms:
"generic return type"
(returns too many results, sorry)Code
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:
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.actually compiles with 3.4.5, and now
c
isundefined
and 3.4.5 thinks it has typenumber
. 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.Playground Link: https://www.typescriptlang.org/play/#src=function%20copy%3CK%20extends%20string%2C%20J%20extends%20string%2C%20T%20extends%20Record%3CK%2C%20number%3E%3E(%0A%20%20%20%20o%3A%20T%2C%20s%3A%20K%2C%20t%3A%20J%0A)%3A%20T%20%26%20Record%3CJ%2C%20number%3E%20%7B%0A%20%20%20%20return%20%7B%20...o%2C%20%5Bt%5D%3A%20o%5Bs%5D%20%7D%3B%0A%7D%0A%0Aconst%20%7B%20c%20%7D%3A%20Record%3C'c'%2C%20number%3E%20%3D%20copy%3C'a'%2C%20'b'%20%7C%20'c'%2C%20Record%3C'a'%2C%20number%3E%3E(%7B%20a%3A%202%20%7D%2C%20'a'%2C%20'b')%3B%0A
Related Issues:
Even found a suspect PR!
Probably introduced in #30769, which I found via #31672.
The text was updated successfully, but these errors were encountered: