-
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
typeof x
now has a string literal union type
#13791
Conversation
Previously, it was just a string
Test that `typeof x === 'random' as string`: 1. Does not issue an error. 2. Does not narrow.
src/compiler/checker.ts
Outdated
@@ -14609,7 +14609,7 @@ namespace ts { | |||
|
|||
function checkTypeOfExpression(node: TypeOfExpression): Type { | |||
checkExpression(node.expression); | |||
return stringType; | |||
return getUnionType(arrayFromMap(typeofEQFacts.keys(), s => getLiteralTypeForText(TypeFlags.StringLiteral, s))); |
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.
can this union type be precomputed and cached to avoid doing the same work multiple times?
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.
Yes. I wasn't sure where to put it though.
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.
Take a look at the new commit; I added a new typeofType
that is created when the checker is.
Note that it changes the print order of string literal unions slightly. I think this is because 'string', 'symbol', etc are added to a union very early in the creation of the checker.
This changes the print order of string literal unions slightly. I think this is because 'string', 'symbol', etc are added to a union very early on in the creation of the checker.
src/compiler/core.ts
Outdated
@@ -895,6 +895,14 @@ namespace ts { | |||
return result; | |||
} | |||
|
|||
export function arrayFromMap<T, U>(iterator: Iterator<T>, f: (value: T) => U) { |
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.
I'd say this is iteratorToArray
to arrayFromIterator
since there is nothing map specific in the signature
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.
I meant map in the sense of the map
function not the Map
type. Maybe mapIterator
? mapIteratorToArray
? Something else?
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.
maybe convertToArray
?
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.
I like that one.
// - when true, removes the primitive types string, number, and boolean from the type of x, or | ||
// - when false, has no effect on the type of x. | ||
|
||
if (typeof strOrC === "Object") { |
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.
is intent here to make C
object in the true branch and string - in false one?
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.
I believe so. Javascript doesn't work that way, of course, so that's why this PR makes it an error.
Note that since 2.0 it has worked this way. Previously, the false branch had no effect on the type of x.
@mhegazy Hey, got linked to this from the interwebs. Was going to adopt TS in SkateJS but it looks like you're making a breaking change as part of a patch milestone? |
Can you elaborate on how SkateJS would be broken by this change? |
2.2.0 is 2.2 RC; 2.2.1 is the release version of 2.2. |
We're not using it yet, but just breaking Skate doesn't concern me. Possibly breaking every consumer on a minor version does. I could be wrong, but this appears to be a change between the 2.1.x stable, minor range to the 2.2.x stable, minor range, correct? I could have easily missed something here.
I apologise for my ignorance, I just couldn't infer that 2.2.1 was the stable after the 2.2 rc. Thanks for clarifying :) |
I see, thanks for the explanation. We make all changes that could result in an error, if previously was not, as "breaking" changes. We promise no breaking changes in revisions, e.g. This change makes the type of |
What the reasoning behind not following semver? Npm docs recommend that modules follow server and will automatically allow minor bumps in a module by default. I'm concerned that not following this convention will create unnecessary friction for TypeScript consumers who will by default be opted in to having their builds broken whenever TypeScript releases a minor version. |
@BenSayers @treshugart the official semver issue is at #14116. You can read some of our reasoning and continue the discussion there. |
typeof x
now has the string literal type'string' | 'number' | 'boolean' | 'symbol' | 'undefined' | 'object' | 'function'
. This will prevent typos and misunderstandings oftypeof
(egtypeof a === "array"
ortypeof o === "null"
). And once #13789 is fixed, it will also provide completions.For implementations that disobey the advice of the standard, it is easy to work around the type, although narrowing no longer works:
Fixes #9506
Fixes #13771 (by making the incorrect narrowing an error)