3 ms·
I thought there were edge cases where sum types were not fully supported, nesting[1] is the example found first, but I thought there were others. [1] https://g
by davorak 2y ago
I thought there were edge cases where sum types were not fully supported, nesting[1] is the example found first, but I thought there were others.
[1] https://github.com/microsoft/TypeScript/issues/18758 https://github.com/microsoft/TypeScript/issues/18758
- int_19h 2y agoPer the comments there, it still works if you use an explicit type guard function for checks, as opposed to checking the nested property directly, so I'd argue that the type itself is still supported in general, just not this particular way of testing for one of the options.
- davorak 2y agoMaybe I am doing something wrong but when I fill in a concrete value for `aOrB` I still get a type error in that example code: Playground Link: https://www.typescriptlang.org/play/?#code/C4TwDgpgBAglC8UDeAoK6qkgLmWjBAdgIYC2EuARDJfugL51TG6ECupARhAE4qMos0AEII8BIblQEiZClErDaBRgU6sO3PgIDGAe0IBnYMwDyPYbjgAfKKMTSMk8TPQlyVJU3oAaJuqgARn4AbhQUfSMTYnNhQ1wAChs7AEoAbQBdMTSmR1dnPNcMd3lFZSLfJjVcYJU-DLCIg2MzCwAmMRiLQzSABgbwgHpBqF4ePR5mQ1GAD0gdYBQASwAzKASu4QA6IS2ShHhEakoU5ChhqCXSMAAbJZ0l4BuQKHJiI0wAC2ITAANN36Xaa-JCYcDyUElKg0KD0ei-JiRQx6G4QLY3PQAcw2sS2xFOFwAojxxtpwis2IQFksDFBvoYACrggBycgAPKzyLNgBBCAATabGHhLQiYgB8GykYJwZyhUCFIsxsN8UDlnIgKVwxCBZwKqrkuHVypc6B4EGAbB4hGYO3BezkB0QJX44VW63pTMg6pxFh8ChoKVOoIuEDmdweTxebw+wG+fwBOpB0oh+o8-soyoRBCRKLRGOxmzxBJGYwmdN40GI0wA7hAbjcXcs1gkPSy5D64n0Mn7joGziGw-dHs9XhB3tNYz8oP9YoClsDQXq5cdM4jmrn0ViOz1+kXziNCHpRiSJo23S2q56IN7Nm0ewGg-vZrch5HR+OvlOZxY5wvk1LlxhOEswwHNUU3AtYjaPcLmZI9S20IA https://www.typescriptlang.org/play/?#code/C4TwDgpgBAglC8UDe... I tried with 5.8.2 and nightly and the results were the same. Interestingly, the playground reports aOrB(from github comment with concrete value) and aOrB2(modified) as the same type, `A | B`, but aOrB will give an error in the typeguarded if block but aOrB2 does not trigger an error. I do not know what is going on there either they do not really have the same type despite the playground reporting both as `A | B` or there is different bug going on. So the solution presented in github does not look like a full solution as is.
- int_19h 2y agoAs far as I can tell, it's failing in the first conditional because it considers the type of `aOrB` to be `B` (rather than `A | B`) even before testing, based on it being initialized to B and then never assigned anything else. So when you apply the type guard, the resulting type of `aOrB` becomes, effectively, `A & B` (intersection), which of course doesn't have member `a`. It would make more sense for TS to treat the body of the if-statement as unreachable and give a warning based on that, but I guess they figured that this kind of thing - doing a type guard on a value that is already known to be of a different type - is a very narrow corner case that isn't worth improving diagnostics for. I'm more curious about why "smuggling" it through an array makes it work. In that case, the type of `aOrB2` remains `A | B` in the conditional, so everything is working as you expected, but I don't see the fundamental difference between this case and the previous one...
- deleted 2y ago[deleted]
- davorak 2y ago> As far as I can tell, it's failing in the first conditional because it considers the type of `aOrB` to be `B`... The playground hover type annotation says aOrB is `A | B` at declaration and if you hover over aOrB in `if (hasTypeName(aOrB, "A"))` it produces `const aOrB: B`. Two types for 1 variable with no operations between. Not clear what operation is being performed on `aOrB`'s type that transforms it or if the playground type hover is just wrong. > It would make more sense for TS to treat the body of the if-statement as unreachable and give a warning based on that, but I guess they figured that this kind of thing - doing a type guard on a value that is already known to be of a different type - is a very narrow corner case that isn't worth improving diagnostics for. That does not seem to be the case, the type guard is not guarding what is in the if block, at least not consistently. It is not about the value being known at least, it is about the property being missing from what I can tell and the guards not being able to guard against it. If you have a top level `a` and `b` in both `A` and `B` there are no errors triggered: type A = { type: { name: "A" } a: number, b: undefined, } type B = { type: { name: "B" } b: number, a: undefined, } const aOrB: A | B = { type: { name: "A" }, a: 1, b: undefined }; // error as expect if (aOrB.type.name === "B") { console.log(aOrB.b) // Error } function hasTypeName<Name extends string>(a: { type: { name: string }}, name: Name): a is { type: { name: Name }} { return a.type.name === name } if (hasTypeName(aOrB, "B")) { console.log(aOrB.b) // no error } if (hasTypeName(aOrB, "A")) { console.log(aOrB.a) // no error here as well } The guards not working or premature type narrowing(the inability to set a variable to a type and have typescript treat it as that type with the above type annotations).