Discriminant property type guard not applied with bracket notation
See original GitHub issueTypeScript Version: 2.0.0
Code
interface Square {
kind: "square";
size: number;
}
interface Rectangle {
kind: "rectangle";
width: number;
height: number;
}
interface Circle {
kind: "circle";
radius: number;
}
type Shape = Square | Rectangle | Circle;
function area(s: Shape) {
// In the following switch statement, the type of s is narrowed in each case clause
// according to the value of the discriminant property, thus allowing the other properties
// of that variant to be accessed without a type assertion.
switch (s['kind']) {
case "square": return s.size * s.size;
case "rectangle": return s.width * s.height;
case "circle": return Math.PI * s.radius * s.radius;
}
}
Expected behavior:
The code compiles without errors.
Actual behavior:
sample.ts(24,33): error TS2339: Property 'size' does not exist on type 'Square | Rectangle | Circle'.
sample.ts(24,42): error TS2339: Property 'size' does not exist on type 'Square | Rectangle | Circle'.
sample.ts(25,36): error TS2339: Property 'width' does not exist on type 'Square | Rectangle | Circle'.
sample.ts(25,46): error TS2339: Property 'height' does not exist on type 'Square | Rectangle | Circle'.
sample.ts(26,43): error TS2339: Property 'radius' does not exist on type 'Square | Rectangle | Circle'.
sample.ts(26,54): error TS2339: Property 'radius' does not exist on type 'Square | Rectangle | Circle'.
Why this is bad:
I am trying to work with Dropbox’s new 2.0 SDK, which heavily uses tagged union types (especially for API errors). The discriminant property is named .tag
, so it can only be accessed via bracket notation. I generated TypeScript typings for their new JavaScript SDK, and discovered this bug the hard way. 😦
Issue Analytics
- State:
- Created 7 years ago
- Reactions:52
- Comments:30 (7 by maintainers)
Top Results From Across the Web
Typescript how to type guard promise type not empty if ...
to act as a discriminated union where the property value located at key 0 is used as the discriminant property.
Read more >Documentation - TypeScript 4.4
If that type guard operates on a const , a readonly property, or an un-modified parameter, then TypeScript is able to narrow that...
Read more >How to properly assign values to a dynamically constructed ...
Discriminant property type guard not applied with bracket notation #10530 · playground const extractShapeTypes: (shapes: ChordShape[]) => IShapeObj ...
Read more >Type guards and assertion functions • Tackling TypeScript
Note that narrowing does not change the original type of value , it only ... If used to check for distinct properties, the...
Read more >property 'usestaticassets' does not exist on type 'inestapplication'
microsoft/TypeScriptDiscriminant property type guard not applied with bracket notation#10530. Created about 6 years ago. 28. TypeScript Version: 2.0.0.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I also found out that variables in bracket notation seem to not work in type guards. Very minimal reproduction:
Playground Link
It seems like using hardcoded values in bracket notation works, which is a fix made in https://github.com/microsoft/TypeScript/issues/28081 however, using a variable doesn’t offer the same behaviour, even if that variable is a
const
. So, it seems inconsistent. I’d understand if the variable was mutable or maybe even an object (perhaps itstoString()
doesn’t return the same thing every time) but for an immutable string variable, this should work the same as a hard-coded value.👍 Bracketed property access should work the same as dotted property access for the purposes of type guards when the indexed name matches a known property