-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Narrowing Union of objects does not return a Union of different narrowed types #54041
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
Comments
I think this falls under the same limitation I described here #54027 (comment) - the compiler doesn’t track where individual values come from (see #30581) |
This feels a lot like #30581; TS doesn't do "distributive control flow analysis" (see #25051). Generally the refactoring needed to get behavior like this is to use generic indexes into mapped types as described in #47109. Doing that here gives me interface SourceMap {
ws: "connecting";
file: number;
}
type Source<K extends keyof SourceMap = keyof SourceMap> =
{ [P in K]: { type: P, reader: { state: SourceMap[P] } } }[K]
type SourceWithState<K extends keyof SourceMap = keyof SourceMap> =
{ [P in K]: { type: P, state: SourceMap[P] } }[K]
function getWithState<K extends keyof SourceMap>(s: Source<K>): SourceWithState<K> {
const type: K = s.type;
const state: SourceMap[K] = s.reader.state;
return { type, state };
}
let source: Source = { type: 'file', reader: { state: 12 } }
const getSourceWithState = () => getWithState(source);
const sourceWithState = getSourceWithState()
if (sourceWithState.type === 'file') {
sourceWithState.state += 1 // okay
} Which works but is much less ergonomic than just throwing a type assertion at the problem and moving on. I don't know if there will be anything better here. |
Thanks for your replies @jcalz & @fatcerberus @jcalz It is exactly what I do usually but I am tired of this complicated mapping and hoped something better would exist. Hope someday this feature can be implemented. |
@jcalz For what it's worth I'm not convinced going all-in on distributive CFA is strictly necessary - most of these cases feel like they could be solved by simply tracking the provenance of types. That would allow the compiler to recognize that const { x, y } = p;
const q = { x, y }; is an isomorphism regardless of the types involved, without having to distribute over any unions (except to construct the final type of the object literal, where it'd distribute over the type of |
Bug Report
When modifying a variable with a type Union of objects, the inferred type should be the Union of the possible results.
🔎 Search Terms
🕗 Version & Regression Information
⏯ Playground Link
Playground link with relevant code
💻 Code
🙁 Actual behavior
The return type of getSourceWithState is
Then trying to narrow the type is impossible.
🙂 Expected behavior
The return type of getSourceWithState should be
This would make it possible to narrow the type and is also the truth.
The text was updated successfully, but these errors were encountered: