Skip to content

Commit 363d914

Browse files
authored
Merge pull request microsoft#13791 from Microsoft/typeof-string-literal-union-type
`typeof x` now has a string literal union type
2 parents a7728f8 + bcd1ef8 commit 363d914

File tree

86 files changed

+560
-741
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+560
-741
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,6 @@ namespace ts {
326326
"object": TypeFacts.TypeofEQObject,
327327
"function": TypeFacts.TypeofEQFunction
328328
});
329-
330329
const typeofNEFacts = createMapFromTemplate({
331330
"string": TypeFacts.TypeofNEString,
332331
"number": TypeFacts.TypeofNENumber,
@@ -336,14 +335,14 @@ namespace ts {
336335
"object": TypeFacts.TypeofNEObject,
337336
"function": TypeFacts.TypeofNEFunction
338337
});
339-
340338
const typeofTypesByName = createMapFromTemplate<Type>({
341339
"string": stringType,
342340
"number": numberType,
343341
"boolean": booleanType,
344342
"symbol": esSymbolType,
345343
"undefined": undefinedType
346344
});
345+
const typeofType = createTypeofType();
347346

348347
let jsxElementType: Type;
349348
let _jsxNamespace: string;
@@ -1727,6 +1726,10 @@ namespace ts {
17271726
return type;
17281727
}
17291728

1729+
function createTypeofType() {
1730+
return getUnionType(convertToArray(typeofEQFacts.keys(), s => getLiteralTypeForText(TypeFlags.StringLiteral, s)));
1731+
}
1732+
17301733
// A reserved member name starts with two underscores, but the third character cannot be an underscore
17311734
// or the @ symbol. A third underscore indicates an escaped form of an identifer that started
17321735
// with at least two underscores. The @ character indicates that the name is denoted by a well known ES
@@ -14626,7 +14629,7 @@ namespace ts {
1462614629

1462714630
function checkTypeOfExpression(node: TypeOfExpression): Type {
1462814631
checkExpression(node.expression);
14629-
return stringType;
14632+
return typeofType;
1463014633
}
1463114634

1463214635
function checkVoidExpression(node: VoidExpression): Type {

src/compiler/core.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -895,6 +895,14 @@ namespace ts {
895895
return result;
896896
}
897897

898+
export function convertToArray<T, U>(iterator: Iterator<T>, f: (value: T) => U) {
899+
const result: U[] = [];
900+
for (let { value, done } = iterator.next(); !done; { value, done } = iterator.next()) {
901+
result.push(f(value));
902+
}
903+
return result;
904+
}
905+
898906
/**
899907
* Calls `callback` for each entry in the map, returning the first truthy result.
900908
* Use `map.forEach` instead for normal iteration.

tests/baselines/reference/TypeGuardWithEnumUnion.types

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function f1(x: Color | string) {
1212

1313
if (typeof x === "number") {
1414
>typeof x === "number" : boolean
15-
>typeof x : string
15+
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
1616
>x : string | Color
1717
>"number" : "number"
1818

@@ -41,7 +41,7 @@ function f2(x: Color | string | string[]) {
4141

4242
if (typeof x === "object") {
4343
>typeof x === "object" : boolean
44-
>typeof x : string
44+
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
4545
>x : string | Color | string[]
4646
>"object" : "object"
4747

@@ -54,7 +54,7 @@ function f2(x: Color | string | string[]) {
5454
}
5555
if (typeof x === "number") {
5656
>typeof x === "number" : boolean
57-
>typeof x : string
57+
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
5858
>x : string | Color | string[]
5959
>"number" : "number"
6060

@@ -76,7 +76,7 @@ function f2(x: Color | string | string[]) {
7676
}
7777
if (typeof x === "string") {
7878
>typeof x === "string" : boolean
79-
>typeof x : string
79+
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
8080
>x : string | Color | string[]
8181
>"string" : "string"
8282

tests/baselines/reference/anonymousClassExpression1.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ function f() {
44

55
return typeof class {} === "function";
66
>typeof class {} === "function" : boolean
7-
>typeof class {} : string
7+
>typeof class {} : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
88
>class {} : typeof (Anonymous class)
99
>"function" : "function"
1010
}

tests/baselines/reference/callSignatureWithoutReturnTypeAnnotationInference.types

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,17 +103,17 @@ var r6 = foo6(1);
103103
>1 : 1
104104

105105
function foo7(x) {
106-
>foo7 : (x: any) => string
106+
>foo7 : (x: any) => "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
107107
>x : any
108108

109109
return typeof x;
110-
>typeof x : string
110+
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
111111
>x : any
112112
}
113113
var r7 = foo7(1);
114-
>r7 : string
115-
>foo7(1) : string
116-
>foo7 : (x: any) => string
114+
>r7 : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
115+
>foo7(1) : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
116+
>foo7 : (x: any) => "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
117117
>1 : 1
118118

119119
// object types

tests/baselines/reference/castExpressionParentheses.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ declare var A;
182182
>(<any>typeof A).x : any
183183
>(<any>typeof A) : any
184184
><any>typeof A : any
185-
>typeof A : string
185+
>typeof A : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
186186
>A : any
187187
>x : any
188188

tests/baselines/reference/castOfAwait.types

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ async function f() {
88
>0 : 0
99

1010
typeof await 0;
11-
>typeof await 0 : string
11+
>typeof await 0 : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
1212
>await 0 : 0
1313
>0 : 0
1414

@@ -21,7 +21,7 @@ async function f() {
2121
>await void <string> typeof <number> void await 0 : any
2222
>void <string> typeof <number> void await 0 : undefined
2323
><string> typeof <number> void await 0 : string
24-
>typeof <number> void await 0 : string
24+
>typeof <number> void await 0 : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
2525
><number> void await 0 : number
2626
>void await 0 : undefined
2727
>await 0 : 0

tests/baselines/reference/classDoesNotDependOnBaseTypes.types

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ var x: StringTree;
55

66
if (typeof x !== "string") {
77
>typeof x !== "string" : boolean
8-
>typeof x : string
8+
>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
99
>x : StringTree
1010
>"string" : "string"
1111

tests/baselines/reference/conditionalOperatorConditionIsBooleanType.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ true ? exprString1 : exprBoolean1; // union
120120
typeof "123" == "string" ? exprBoolean1 : exprBoolean2;
121121
>typeof "123" == "string" ? exprBoolean1 : exprBoolean2 : boolean
122122
>typeof "123" == "string" : boolean
123-
>typeof "123" : string
123+
>typeof "123" : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
124124
>"123" : "123"
125125
>"string" : "string"
126126
>exprBoolean1 : boolean
@@ -262,7 +262,7 @@ var resultIsBoolean3 = typeof "123" == "string" ? exprBoolean1 : exprBoolean2;
262262
>resultIsBoolean3 : boolean
263263
>typeof "123" == "string" ? exprBoolean1 : exprBoolean2 : boolean
264264
>typeof "123" == "string" : boolean
265-
>typeof "123" : string
265+
>typeof "123" : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
266266
>"123" : "123"
267267
>"string" : "string"
268268
>exprBoolean1 : boolean
@@ -299,7 +299,7 @@ var resultIsStringOrBoolean4 = typeof "123" === "string" ? exprString1 : exprBoo
299299
>resultIsStringOrBoolean4 : string | boolean
300300
>typeof "123" === "string" ? exprString1 : exprBoolean1 : string | boolean
301301
>typeof "123" === "string" : boolean
302-
>typeof "123" : string
302+
>typeof "123" : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
303303
>"123" : "123"
304304
>"string" : "string"
305305
>exprString1 : string

tests/baselines/reference/conditionalOperatorConditoinIsStringType.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ var array = ["1", "2", "3"];
123123

124124
typeof condString ? exprAny1 : exprAny2;
125125
>typeof condString ? exprAny1 : exprAny2 : any
126-
>typeof condString : string
126+
>typeof condString : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
127127
>condString : string
128128
>exprAny1 : any
129129
>exprAny2 : any
@@ -254,7 +254,7 @@ var resultIsStringOrBoolean2 = "hello" ? exprString1 : exprBoolean1; // union
254254
var resultIsAny3 = typeof condString ? exprAny1 : exprAny2;
255255
>resultIsAny3 : any
256256
>typeof condString ? exprAny1 : exprAny2 : any
257-
>typeof condString : string
257+
>typeof condString : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
258258
>condString : string
259259
>exprAny1 : any
260260
>exprAny2 : any
@@ -297,7 +297,7 @@ var resultIsObject3 = array[1] ? exprIsObject1 : exprIsObject2;
297297
var resultIsStringOrBoolean3 = typeof condString ? exprString1 : exprBoolean1; // union
298298
>resultIsStringOrBoolean3 : string | boolean
299299
>typeof condString ? exprString1 : exprBoolean1 : string | boolean
300-
>typeof condString : string
300+
>typeof condString : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function"
301301
>condString : string
302302
>exprString1 : string
303303
>exprBoolean1 : boolean

0 commit comments

Comments
 (0)