-
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
[Suggestion] Disallow literal types to be asserted to a different literal type of the same widened type #14156
Comments
Just ran into this specifically with string literals and was about to log an issue. I was just trying to use
Upvoted. :) |
I've always been worried that I might make an error while typing the discrimination string twice in ad-hoc unions. However, the turning point for me was the realisation that we can easily achieve compile-time |
This is allowed because we widen the type of the expression before testing if it's comparable to the asserted type. Widening is important so that |
Just for clarification: null as 1; // error in strictNullChecks
null! as 1; // OK, even in strictNullChecks
null as any as 1; // also OK Widening is sometimes beneficial and should be applied, e.g. when faking nominal types with brands. '/dev/null' as (string & { _pathBrand: any }); // currently OK and should be OK Widening is counter intuitive when asserting two distinct literal types, if both types have the same base type. 'hello' as 'goodbye'; // currently allowed, but it shouldn't!
123 as true; // different base types - error in before and after |
asserting |
You can use a double cast when you are intentionally cheating |
Discussed and overall we think this behavior is preferable to the alternative. In general we allow "plausible" type assertions and a literal-to-literal cast within the same primitive type qualifies under that metric. Somewhat frequently you have to do this when a side effect unknown to the compiler changes a previously-guarded symbol, e.g. var x = true;
// ...
mutateXfromAfar();
// hit some specific overload
var j = doSomething(x as false); Double casting is always an option but just seems too cumbersome here; I think as much as possible you should always be able to write non-suspicious code without ever having to double-cast. |
Casting to a different literal definitely falls in the category of suspicios, imo. Casting to base - sure. Calling apples oranges can't be right. |
If someone knows of a tslint rule that checks for this, that would be valuable, and it would be appreciated if it was linked here! |
I have an initial implementation of a lint rule to checks exactly what is described in this issue. Be aware that this is not a TSLint rule. It's a rule for the Fimbullinter project (which might supersede TSLint in the future). So you need to use yet another linting tool to detect some real bugs. |
TypeScript Version: nightly (2.3.0-dev.20170217)
The problem
Currently it is possible to assert an expression of one literal type to be of a different literal type.
This is confusing and obviously incorrect. It also diverges from the behaviour exhibited when checking literal properties and array elements. The following cases raise errors as expected.
It's been written many times that assertions provide a mechanism to either upcast or downcast, however in the specific case of mismatching literal types, the operation is actually coercion because they are on the same level.
Proposal
No literal widening should be carried out prior to the assertion compatibility check iff the expression type is a string, number or boolean literal and the assertion type is
Examples
The text was updated successfully, but these errors were encountered: