Skip to content

Commit 76e71ab

Browse files
authored
Merge pull request #11126 from Microsoft/nonWideningLiterals
Non-widening explicit literal types
2 parents 3d92117 + b6b8e8c commit 76e71ab

File tree

48 files changed

+1448
-231
lines changed

Some content is hidden

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

48 files changed

+1448
-231
lines changed

src/compiler/checker.ts

+152-45
Large diffs are not rendered by default.

src/compiler/declarationEmitter.ts

+4
Original file line numberDiff line numberDiff line change
@@ -1142,6 +1142,10 @@ namespace ts {
11421142
if ((node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertySignature) && node.parent.kind === SyntaxKind.TypeLiteral) {
11431143
emitTypeOfVariableDeclarationFromTypeLiteral(node);
11441144
}
1145+
else if (resolver.isLiteralConstDeclaration(node)) {
1146+
write(" = ");
1147+
resolver.writeLiteralConstValue(node, writer);
1148+
}
11451149
else if (!hasModifier(node, ModifierFlags.Private)) {
11461150
writeTypeOfDeclaration(node, node.type, getVariableDeclarationTypeVisibilityError);
11471151
}

src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,10 @@
819819
"category": "Error",
820820
"code": 1253
821821
},
822+
"A 'const' initializer in an ambient context must be a string or numeric literal.": {
823+
"category": "Error",
824+
"code": 1254
825+
},
822826
"'with' statements are not allowed in an async function block.": {
823827
"category": "Error",
824828
"code": 1300

src/compiler/types.ts

+10-4
Original file line numberDiff line numberDiff line change
@@ -2167,6 +2167,8 @@ namespace ts {
21672167
getExternalModuleFileFromDeclaration(declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration): SourceFile;
21682168
getTypeReferenceDirectivesForEntityName(name: EntityNameOrEntityNameExpression): string[];
21692169
getTypeReferenceDirectivesForSymbol(symbol: Symbol, meaning?: SymbolFlags): string[];
2170+
isLiteralConstDeclaration(node: VariableDeclaration): boolean;
2171+
writeLiteralConstValue(node: VariableDeclaration, writer: SymbolWriter): void;
21702172
}
21712173

21722174
export const enum SymbolFlags {
@@ -2383,7 +2385,7 @@ namespace ts {
23832385
/* @internal */
23842386
ObjectLiteral = 1 << 23, // Originates in an object literal
23852387
/* @internal */
2386-
FreshObjectLiteral = 1 << 24, // Fresh object literal type
2388+
FreshLiteral = 1 << 24, // Fresh literal type
23872389
/* @internal */
23882390
ContainsWideningType = 1 << 25, // Type is or contains undefined or null widening type
23892391
/* @internal */
@@ -2396,6 +2398,7 @@ namespace ts {
23962398
/* @internal */
23972399
Nullable = Undefined | Null,
23982400
Literal = StringLiteral | NumberLiteral | BooleanLiteral | EnumLiteral,
2401+
StringOrNumberLiteral = StringLiteral | NumberLiteral,
23992402
/* @internal */
24002403
DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null,
24012404
PossiblyFalsy = DefinitelyFalsy | String | Number | Boolean,
@@ -2437,12 +2440,15 @@ namespace ts {
24372440
/* @internal */
24382441
// Intrinsic types (TypeFlags.Intrinsic)
24392442
export interface IntrinsicType extends Type {
2440-
intrinsicName: string; // Name of intrinsic type
2443+
intrinsicName: string; // Name of intrinsic type
24412444
}
24422445

24432446
// String literal types (TypeFlags.StringLiteral)
2447+
// Numeric literal types (TypeFlags.NumberLiteral)
24442448
export interface LiteralType extends Type {
2445-
text: string; // Text of string literal
2449+
text: string; // Text of literal
2450+
freshType?: LiteralType; // Fresh version of type
2451+
regularType?: LiteralType; // Regular version of type
24462452
}
24472453

24482454
// Enum types (TypeFlags.Enum)
@@ -2452,7 +2458,7 @@ namespace ts {
24522458

24532459
// Enum types (TypeFlags.EnumLiteral)
24542460
export interface EnumLiteralType extends LiteralType {
2455-
baseType: EnumType & UnionType;
2461+
baseType: EnumType & UnionType; // Base enum type
24562462
}
24572463

24582464
// Object types (TypeFlags.ObjectType)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//// [ambientConstLiterals.ts]
2+
3+
function f<T>(x: T): T {
4+
return x;
5+
}
6+
7+
enum E { A, B, C }
8+
9+
const c1 = "abc";
10+
const c2 = 123;
11+
const c3 = c1;
12+
const c4 = c2;
13+
const c5 = f(123);
14+
const c6 = f(-123);
15+
const c7 = true;
16+
const c8 = E.A;
17+
const c9 = { x: "abc" };
18+
const c10 = [123];
19+
const c11 = "abc" + "def";
20+
const c12 = 123 + 456;
21+
const c13 = Math.random() > 0.5 ? "abc" : "def";
22+
const c14 = Math.random() > 0.5 ? 123 : 456;
23+
24+
//// [ambientConstLiterals.js]
25+
function f(x) {
26+
return x;
27+
}
28+
var E;
29+
(function (E) {
30+
E[E["A"] = 0] = "A";
31+
E[E["B"] = 1] = "B";
32+
E[E["C"] = 2] = "C";
33+
})(E || (E = {}));
34+
var c1 = "abc";
35+
var c2 = 123;
36+
var c3 = c1;
37+
var c4 = c2;
38+
var c5 = f(123);
39+
var c6 = f(-123);
40+
var c7 = true;
41+
var c8 = E.A;
42+
var c9 = { x: "abc" };
43+
var c10 = [123];
44+
var c11 = "abc" + "def";
45+
var c12 = 123 + 456;
46+
var c13 = Math.random() > 0.5 ? "abc" : "def";
47+
var c14 = Math.random() > 0.5 ? 123 : 456;
48+
49+
50+
//// [ambientConstLiterals.d.ts]
51+
declare function f<T>(x: T): T;
52+
declare enum E {
53+
A = 0,
54+
B = 1,
55+
C = 2,
56+
}
57+
declare const c1 = "abc";
58+
declare const c2 = 123;
59+
declare const c3 = "abc";
60+
declare const c4 = 123;
61+
declare const c5 = 123;
62+
declare const c6 = -123;
63+
declare const c7: boolean;
64+
declare const c8: E;
65+
declare const c9: {
66+
x: string;
67+
};
68+
declare const c10: number[];
69+
declare const c11: string;
70+
declare const c12: number;
71+
declare const c13: string;
72+
declare const c14: number;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
=== tests/cases/compiler/ambientConstLiterals.ts ===
2+
3+
function f<T>(x: T): T {
4+
>f : Symbol(f, Decl(ambientConstLiterals.ts, 0, 0))
5+
>T : Symbol(T, Decl(ambientConstLiterals.ts, 1, 11))
6+
>x : Symbol(x, Decl(ambientConstLiterals.ts, 1, 14))
7+
>T : Symbol(T, Decl(ambientConstLiterals.ts, 1, 11))
8+
>T : Symbol(T, Decl(ambientConstLiterals.ts, 1, 11))
9+
10+
return x;
11+
>x : Symbol(x, Decl(ambientConstLiterals.ts, 1, 14))
12+
}
13+
14+
enum E { A, B, C }
15+
>E : Symbol(E, Decl(ambientConstLiterals.ts, 3, 1))
16+
>A : Symbol(E.A, Decl(ambientConstLiterals.ts, 5, 8))
17+
>B : Symbol(E.B, Decl(ambientConstLiterals.ts, 5, 11))
18+
>C : Symbol(E.C, Decl(ambientConstLiterals.ts, 5, 14))
19+
20+
const c1 = "abc";
21+
>c1 : Symbol(c1, Decl(ambientConstLiterals.ts, 7, 5))
22+
23+
const c2 = 123;
24+
>c2 : Symbol(c2, Decl(ambientConstLiterals.ts, 8, 5))
25+
26+
const c3 = c1;
27+
>c3 : Symbol(c3, Decl(ambientConstLiterals.ts, 9, 5))
28+
>c1 : Symbol(c1, Decl(ambientConstLiterals.ts, 7, 5))
29+
30+
const c4 = c2;
31+
>c4 : Symbol(c4, Decl(ambientConstLiterals.ts, 10, 5))
32+
>c2 : Symbol(c2, Decl(ambientConstLiterals.ts, 8, 5))
33+
34+
const c5 = f(123);
35+
>c5 : Symbol(c5, Decl(ambientConstLiterals.ts, 11, 5))
36+
>f : Symbol(f, Decl(ambientConstLiterals.ts, 0, 0))
37+
38+
const c6 = f(-123);
39+
>c6 : Symbol(c6, Decl(ambientConstLiterals.ts, 12, 5))
40+
>f : Symbol(f, Decl(ambientConstLiterals.ts, 0, 0))
41+
42+
const c7 = true;
43+
>c7 : Symbol(c7, Decl(ambientConstLiterals.ts, 13, 5))
44+
45+
const c8 = E.A;
46+
>c8 : Symbol(c8, Decl(ambientConstLiterals.ts, 14, 5))
47+
>E.A : Symbol(E.A, Decl(ambientConstLiterals.ts, 5, 8))
48+
>E : Symbol(E, Decl(ambientConstLiterals.ts, 3, 1))
49+
>A : Symbol(E.A, Decl(ambientConstLiterals.ts, 5, 8))
50+
51+
const c9 = { x: "abc" };
52+
>c9 : Symbol(c9, Decl(ambientConstLiterals.ts, 15, 5))
53+
>x : Symbol(x, Decl(ambientConstLiterals.ts, 15, 12))
54+
55+
const c10 = [123];
56+
>c10 : Symbol(c10, Decl(ambientConstLiterals.ts, 16, 5))
57+
58+
const c11 = "abc" + "def";
59+
>c11 : Symbol(c11, Decl(ambientConstLiterals.ts, 17, 5))
60+
61+
const c12 = 123 + 456;
62+
>c12 : Symbol(c12, Decl(ambientConstLiterals.ts, 18, 5))
63+
64+
const c13 = Math.random() > 0.5 ? "abc" : "def";
65+
>c13 : Symbol(c13, Decl(ambientConstLiterals.ts, 19, 5))
66+
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
67+
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
68+
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))
69+
70+
const c14 = Math.random() > 0.5 ? 123 : 456;
71+
>c14 : Symbol(c14, Decl(ambientConstLiterals.ts, 20, 5))
72+
>Math.random : Symbol(Math.random, Decl(lib.d.ts, --, --))
73+
>Math : Symbol(Math, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
74+
>random : Symbol(Math.random, Decl(lib.d.ts, --, --))
75+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
=== tests/cases/compiler/ambientConstLiterals.ts ===
2+
3+
function f<T>(x: T): T {
4+
>f : <T>(x: T) => T
5+
>T : T
6+
>x : T
7+
>T : T
8+
>T : T
9+
10+
return x;
11+
>x : T
12+
}
13+
14+
enum E { A, B, C }
15+
>E : E
16+
>A : E.A
17+
>B : E.B
18+
>C : E.C
19+
20+
const c1 = "abc";
21+
>c1 : "abc"
22+
>"abc" : "abc"
23+
24+
const c2 = 123;
25+
>c2 : 123
26+
>123 : 123
27+
28+
const c3 = c1;
29+
>c3 : "abc"
30+
>c1 : "abc"
31+
32+
const c4 = c2;
33+
>c4 : 123
34+
>c2 : 123
35+
36+
const c5 = f(123);
37+
>c5 : 123
38+
>f(123) : 123
39+
>f : <T>(x: T) => T
40+
>123 : 123
41+
42+
const c6 = f(-123);
43+
>c6 : -123
44+
>f(-123) : -123
45+
>f : <T>(x: T) => T
46+
>-123 : -123
47+
>123 : 123
48+
49+
const c7 = true;
50+
>c7 : true
51+
>true : true
52+
53+
const c8 = E.A;
54+
>c8 : E.A
55+
>E.A : E.A
56+
>E : typeof E
57+
>A : E.A
58+
59+
const c9 = { x: "abc" };
60+
>c9 : { x: string; }
61+
>{ x: "abc" } : { x: string; }
62+
>x : string
63+
>"abc" : "abc"
64+
65+
const c10 = [123];
66+
>c10 : number[]
67+
>[123] : number[]
68+
>123 : 123
69+
70+
const c11 = "abc" + "def";
71+
>c11 : string
72+
>"abc" + "def" : string
73+
>"abc" : "abc"
74+
>"def" : "def"
75+
76+
const c12 = 123 + 456;
77+
>c12 : number
78+
>123 + 456 : number
79+
>123 : 123
80+
>456 : 456
81+
82+
const c13 = Math.random() > 0.5 ? "abc" : "def";
83+
>c13 : "abc" | "def"
84+
>Math.random() > 0.5 ? "abc" : "def" : "abc" | "def"
85+
>Math.random() > 0.5 : boolean
86+
>Math.random() : number
87+
>Math.random : () => number
88+
>Math : Math
89+
>random : () => number
90+
>0.5 : 0.5
91+
>"abc" : "abc"
92+
>"def" : "def"
93+
94+
const c14 = Math.random() > 0.5 ? 123 : 456;
95+
>c14 : 123 | 456
96+
>Math.random() > 0.5 ? 123 : 456 : 123 | 456
97+
>Math.random() > 0.5 : boolean
98+
>Math.random() : number
99+
>Math.random : () => number
100+
>Math : Math
101+
>random : () => number
102+
>0.5 : 0.5
103+
>123 : 123
104+
>456 : 456
105+

tests/baselines/reference/arrayconcat.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class parser {
4646
>this : this
4747
>options : IOptions[]
4848
>sort : (compareFn?: (a: IOptions, b: IOptions) => number) => IOptions[]
49-
>function(a, b) { var aName = a.name.toLowerCase(); var bName = b.name.toLowerCase(); if (aName > bName) { return 1; } else if (aName < bName) { return -1; } else { return 0; } } : (a: IOptions, b: IOptions) => 0 | 1 | -1
49+
>function(a, b) { var aName = a.name.toLowerCase(); var bName = b.name.toLowerCase(); if (aName > bName) { return 1; } else if (aName < bName) { return -1; } else { return 0; } } : (a: IOptions, b: IOptions) => 1 | -1 | 0
5050
>a : IOptions
5151
>b : IOptions
5252

tests/baselines/reference/bestCommonTypeOfConditionalExpressions2.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ var derived2: Derived2;
3030

3131
var r2 = true ? 1 : '';
3232
>r2 : string | number
33-
>true ? 1 : '' : "" | 1
33+
>true ? 1 : '' : 1 | ""
3434
>true : true
3535
>1 : 1
3636
>'' : ""

tests/baselines/reference/computedPropertyNamesContextualType6_ES5.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ declare function foo<T>(obj: I<T>): T
1919
foo({
2020
>foo({ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]}) : string | number | boolean | (() => void) | number[]
2121
>foo : <T>(obj: I<T>) => T
22-
>{ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]} : { [x: string]: true | "" | 0 | (() => void) | number[]; [x: number]: 0 | (() => void) | number[]; 0: () => void; p: ""; }
22+
>{ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]} : { [x: string]: true | "" | (() => void) | 0 | number[]; [x: number]: (() => void) | 0 | number[]; 0: () => void; p: ""; }
2323

2424
p: "",
2525
>p : string

tests/baselines/reference/computedPropertyNamesContextualType6_ES6.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ declare function foo<T>(obj: I<T>): T
1919
foo({
2020
>foo({ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]}) : string | number | boolean | (() => void) | number[]
2121
>foo : <T>(obj: I<T>) => T
22-
>{ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]} : { [x: string]: true | "" | 0 | (() => void) | number[]; [x: number]: 0 | (() => void) | number[]; 0: () => void; p: ""; }
22+
>{ p: "", 0: () => { }, ["hi" + "bye"]: true, [0 + 1]: 0, [+"hi"]: [0]} : { [x: string]: true | "" | (() => void) | 0 | number[]; [x: number]: (() => void) | 0 | number[]; 0: () => void; p: ""; }
2323

2424
p: "",
2525
>p : string
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
tests/cases/compiler/conditionalExpression1.ts(1,5): error TS2322: Type '"" | 1' is not assignable to type 'boolean'.
2-
Type '""' is not assignable to type 'boolean'.
1+
tests/cases/compiler/conditionalExpression1.ts(1,5): error TS2322: Type '1 | ""' is not assignable to type 'boolean'.
2+
Type '1' is not assignable to type 'boolean'.
33

44

55
==== tests/cases/compiler/conditionalExpression1.ts (1 errors) ====
66
var x: boolean = (true ? 1 : ""); // should be an error
77
~
8-
!!! error TS2322: Type '"" | 1' is not assignable to type 'boolean'.
9-
!!! error TS2322: Type '""' is not assignable to type 'boolean'.
8+
!!! error TS2322: Type '1 | ""' is not assignable to type 'boolean'.
9+
!!! error TS2322: Type '1' is not assignable to type 'boolean'.

tests/baselines/reference/conditionalExpressions2.types

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ var b = false ? undefined : 0;
1616

1717
var c = false ? 1 : 0;
1818
>c : number
19-
>false ? 1 : 0 : 0 | 1
19+
>false ? 1 : 0 : 1 | 0
2020
>false : false
2121
>1 : 1
2222
>0 : 0

0 commit comments

Comments
 (0)