-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Allow partial unions for indexed type access #22094
Allow partial unions for indexed type access #22094
Conversation
@ahejlsberg take a look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, but needs the suggested change. Also, please add a test to ensure the expected error is reported.
src/compiler/checker.ts
Outdated
@@ -7997,7 +8003,7 @@ namespace ts { | |||
getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>accessExpression.argumentExpression).name)) : | |||
undefined; | |||
if (propName !== undefined) { | |||
const prop = getPropertyOfType(objectType, propName); | |||
const prop = getPropertyOfType(objectType, propName, /*allowPartialUnions*/ true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a too permissive. For example, it will allow the following to compile with no error:
interface Foo {
bar: { baz: string } | { qux: number }
}
function f(x: Foo) {
return x['bar']['baz']; // Should be an error
}
It's pretty easy to fix through:
const prop = getPropertyOfType(objectType, propName, !accessExpression);
This will allow partial unions only when the indexed access doesn't originate in an expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah good catch. Fixed! Thanks for the review @ahejlsberg
@ahejlsberg any more comments? |
We actually have a |
u mean generic type? the idea is not to force users to write the type reference if all what they want is to get to the type of the property. |
I don't think it's a good idea to implicitly filter the union given to only the applicable elements, since now conditional types exist and allow users to explicitly perform that filtering if need be themselves. |
Like, index has the nice property that that's the inverse of a mapped type right now, this breaks that - a mapped type will never produce multiple "possible" object types. |
I'm going to insist that this does not feel like a primitive operation anymore when you do this. You can easily write an For posterity: Note how I had to use our current index operator in the definition. If index becomes loose by default, writing a strict version becomes impossible because there's no way to write a type that can trigger the same errors... |
Sorry I don't entirely follow. Can conditional types be used to do the following? interface Foo {
bar: {
baz: string;
} | {
qux: number;
}
}
type ShouldBeString = Foo['bar']['baz']; What favorable errors would be impossible after this change? Could you give an example? |
OK, I have added this issue to the agenda of the next design meeting; let's see if we can reach consensuses about this. |
Discussed this again in #22445. Conclusion, with |
Solves #21975 and #14366 by allowing partial union types for indexed type access as opposed to creating a null assertion type operator.
@mhegazy @DanielRosenwasser
Fixes #21975
Fixes #14366
Related #16108