-
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
Surprising/incorrect composition of generic type functions (when one is a mapped type) #17908
Comments
type KeyofPropertyofFooBroken = KeyofPropertyof<Foo>; // never; broken
function the<T, V extends T>() {} // check type matches without having to name your types
the<never, string>(); // correctly errors with ... does not satisfy ...
the<Valueof<KeyofPropertyof<Foo>>, 'prop1' | 'prop2'>(); // LHS would be `never` yet doesn't error? That's definitely odd. It's |
I'm not sure why you did the<Valueof<KeyofPropertyof<Foo>>, 'prop1' | 'prop2'>(); // LHS is any since that's something like If you do the<KeyofPropertyof<Foo>, 'prop1' | 'prop2'>(); // LHS is 'never' and does error it does indicate that |
I think that's the default type on error. Your test is definitely better to verify the issue, yeah. 😅 |
Ah, applying the amazing workaround by @gcanti: type KeyofPropertyof<T, X=MappedKeyof<T>> = Valueof<X>;
type KeyofPropertyofFoo = KeyofPropertyof<Foo> // 'prop1'|'prop2' And so, in general, the workaround for type A = ...
type F<T> = ...
type G<T> = ...
type FoG<T> = F<G<T>> //broken is type FoG<T, GT=G<T>> = F<GT> // works I guess I can live with this if it can't be fixed otherwise, although it's confusing enough that I'd be loath to introduce it in an answer to someone's question on SO. |
Yeah still seems a bug. Sorry I hadn't suggested it, presumed you'd tried since it was raised in both of the other threads you linked. :P |
Indeed. I guess I didn't read them well enough. 🚫👀❗️ And yeah, the workaround is not helping me in the more general issue that I pared down to the above snippet. Seems like I keep having to break things apart into multiple steps and introduce concrete types early in order to build something, which is bad for users of a library. |
Hmm, since #15756 is now fixed, I wonder if this issue is also? |
@jcalz: just tried on master -- it is! |
When trying to compose generic type aliases I've run into some instances where the compiler breaks the intended semantics. Here is as small/self-contained an example as I can come up with:
TypeScript Version: 2.4.0 / nightly (2.5.0-dev.20170627)
Code
Expected behavior:
I expect
KeyofPropertyof<Foo>
to be equivalent toValueof<MappedKeyof<Foo>>
.Actual behavior:
What's
KeyofPropertyof<T>
doing? Quickinfo saystype KeyofPropertyof<T> = keyof (T[keyof T])
. So it tookValueof<MappedKeyof<T>>
and "simplified" it tokeyof Valueof<T>
, but that's the intersection of the keys of the properties, not the union. Hence thenever
instead of'prop1'|'prop2'
🙁In general, given
I expect
F<G<A>>
to be equivalent toFoG<A>
. Anything else makes it very hard to reason about what is going on.This seems like something @tycho01 has run into before: is it the same issue as #16244 and/or #16018? Is it a bug? design limitation? intention? there any way to work around it in general? My use cases here are mostly type manipulation in the absence of built-in subtraction/exact/conditional mapped types. Someone on Stack Overflow asks a question, I try to build something that solves the problem, and I hit this.
Thoughts? Thanks!
The text was updated successfully, but these errors were encountered: