Skip to content

Commit 62d8b85

Browse files
authored
Allow literal initializers of readonly properties in declaration files (#26313)
* Allow literal initializers of readonly properties in declaration files * Move some conditions a bit
1 parent bcb815b commit 62d8b85

16 files changed

+147
-89
lines changed

src/compiler/checker.ts

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21708,7 +21708,7 @@ namespace ts {
2170821708
const initializer = getEffectiveInitializer(declaration)!;
2170921709
const type = getTypeOfExpression(initializer, /*cache*/ true);
2171021710
const widened = getCombinedNodeFlags(declaration) & NodeFlags.Const ||
21711-
(getCombinedModifierFlags(declaration) & ModifierFlags.Readonly && !isParameterPropertyDeclaration(declaration)) ||
21711+
isDeclarationReadonly(declaration) ||
2171221712
isTypeAssertion(initializer) ? type : getWidenedLiteralType(type);
2171321713
if (isInJavaScriptFile(declaration)) {
2171421714
if (widened.flags & TypeFlags.Nullable) {
@@ -28082,7 +28082,7 @@ namespace ts {
2808228082
}
2808328083

2808428084
function isLiteralConstDeclaration(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): boolean {
28085-
if (isVariableDeclaration(node) && isVarConst(node)) {
28085+
if (isDeclarationReadonly(node) || isVariableDeclaration(node) && isVarConst(node)) {
2808628086
const type = getTypeOfSymbol(getSymbolOfNode(node));
2808728087
return !!(type.flags & TypeFlags.StringOrNumberLiteral && type.flags & TypeFlags.FreshLiteral);
2808828088
}
@@ -29420,26 +29420,28 @@ namespace ts {
2942029420
(<PrefixUnaryExpression>expr).operand.kind === SyntaxKind.NumericLiteral;
2942129421
}
2942229422

29423+
function checkAmbientInitializer(node: VariableDeclaration | PropertyDeclaration | PropertySignature) {
29424+
if (node.initializer) {
29425+
const isInvalidInitializer = !isStringOrNumberLiteralExpression(node.initializer);
29426+
const isConstOrReadonly = isDeclarationReadonly(node) || isVariableDeclaration(node) && isVarConst(node);
29427+
if (isConstOrReadonly && !node.type) {
29428+
if (isInvalidInitializer) {
29429+
return grammarErrorOnNode(node.initializer!, Diagnostics.A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal);
29430+
}
29431+
}
29432+
else {
29433+
return grammarErrorOnNode(node.initializer!, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
29434+
}
29435+
if (!isConstOrReadonly || isInvalidInitializer) {
29436+
return grammarErrorOnNode(node.initializer!, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
29437+
}
29438+
}
29439+
}
29440+
2942329441
function checkGrammarVariableDeclaration(node: VariableDeclaration) {
2942429442
if (node.parent.parent.kind !== SyntaxKind.ForInStatement && node.parent.parent.kind !== SyntaxKind.ForOfStatement) {
2942529443
if (node.flags & NodeFlags.Ambient) {
29426-
if (node.initializer) {
29427-
if (isVarConst(node) && !node.type) {
29428-
if (!isStringOrNumberLiteralExpression(node.initializer)) {
29429-
return grammarErrorOnNode(node.initializer, Diagnostics.A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal);
29430-
}
29431-
}
29432-
else {
29433-
// Error on equals token which immediate precedes the initializer
29434-
const equalsTokenLength = "=".length;
29435-
return grammarErrorAtPos(node, node.initializer.pos - equalsTokenLength, equalsTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
29436-
}
29437-
}
29438-
if (node.initializer && !(isVarConst(node) && isStringOrNumberLiteralExpression(node.initializer))) {
29439-
// Error on equals token which immediate precedes the initializer
29440-
const equalsTokenLength = "=".length;
29441-
return grammarErrorAtPos(node, node.initializer.pos - equalsTokenLength, equalsTokenLength, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
29442-
}
29444+
checkAmbientInitializer(node);
2944329445
}
2944429446
else if (!node.initializer) {
2944529447
if (isBindingPattern(node.name) && !isBindingPattern(node.parent)) {
@@ -29632,8 +29634,8 @@ namespace ts {
2963229634
}
2963329635
}
2963429636

29635-
if (node.flags & NodeFlags.Ambient && node.initializer) {
29636-
return grammarErrorOnFirstToken(node.initializer, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts);
29637+
if (node.flags & NodeFlags.Ambient) {
29638+
checkAmbientInitializer(node);
2963729639
}
2963829640

2963929641
if (isPropertyDeclaration(node) && node.exclamationToken && (!isClassLike(node.parent) || !node.type || node.initializer ||

src/compiler/utilities.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,10 @@ namespace ts {
922922
return !!(getCombinedModifierFlags(node) & ModifierFlags.Const);
923923
}
924924

925+
export function isDeclarationReadonly(declaration: Declaration): boolean {
926+
return !!(getCombinedModifierFlags(declaration) & ModifierFlags.Readonly && !isParameterPropertyDeclaration(declaration));
927+
}
928+
925929
export function isVarConst(node: VariableDeclaration | VariableDeclarationList): boolean {
926930
return !!(getCombinedNodeFlags(node) & NodeFlags.Const);
927931
}

tests/baselines/reference/ambientErrors.errors.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
tests/cases/conformance/ambient/ambientErrors.ts(2,15): error TS1039: Initializers are not allowed in ambient contexts.
1+
tests/cases/conformance/ambient/ambientErrors.ts(2,17): error TS1039: Initializers are not allowed in ambient contexts.
22
tests/cases/conformance/ambient/ambientErrors.ts(17,22): error TS2371: A parameter initializer is only allowed in a function or constructor implementation.
33
tests/cases/conformance/ambient/ambientErrors.ts(20,24): error TS1183: An implementation cannot be declared in ambient contexts.
44
tests/cases/conformance/ambient/ambientErrors.ts(29,9): error TS1066: In ambient enum declarations member initializer must be constant expression.
5-
tests/cases/conformance/ambient/ambientErrors.ts(34,11): error TS1039: Initializers are not allowed in ambient contexts.
5+
tests/cases/conformance/ambient/ambientErrors.ts(34,13): error TS1039: Initializers are not allowed in ambient contexts.
66
tests/cases/conformance/ambient/ambientErrors.ts(35,19): error TS1183: An implementation cannot be declared in ambient contexts.
77
tests/cases/conformance/ambient/ambientErrors.ts(37,20): error TS1039: Initializers are not allowed in ambient contexts.
88
tests/cases/conformance/ambient/ambientErrors.ts(38,13): error TS1039: Initializers are not allowed in ambient contexts.
@@ -17,7 +17,7 @@ tests/cases/conformance/ambient/ambientErrors.ts(57,5): error TS2309: An export
1717
==== tests/cases/conformance/ambient/ambientErrors.ts (14 errors) ====
1818
// Ambient variable with an initializer
1919
declare var x = 4;
20-
~
20+
~
2121
!!! error TS1039: Initializers are not allowed in ambient contexts.
2222

2323
// Ambient functions with invalid overloads
@@ -57,7 +57,7 @@ tests/cases/conformance/ambient/ambientErrors.ts(57,5): error TS2309: An export
5757
// Ambient module with initializers for values, bodies for functions / classes
5858
declare module M1 {
5959
var x = 3;
60-
~
60+
~
6161
!!! error TS1039: Initializers are not allowed in ambient contexts.
6262
function fn() { }
6363
~
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
tests/cases/compiler/ambientErrors1.ts(1,15): error TS1039: Initializers are not allowed in ambient contexts.
1+
tests/cases/compiler/ambientErrors1.ts(1,17): error TS1039: Initializers are not allowed in ambient contexts.
22

33

44
==== tests/cases/compiler/ambientErrors1.ts (1 errors) ====
55
declare var x = 4;
6-
~
6+
~
77
!!! error TS1039: Initializers are not allowed in ambient contexts.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
tests/cases/compiler/ambientStatement1.ts(2,6): error TS1036: Statements are not allowed in ambient contexts.
2-
tests/cases/compiler/ambientStatement1.ts(4,20): error TS1039: Initializers are not allowed in ambient contexts.
2+
tests/cases/compiler/ambientStatement1.ts(4,22): error TS1039: Initializers are not allowed in ambient contexts.
33

44

55
==== tests/cases/compiler/ambientStatement1.ts (2 errors) ====
@@ -9,6 +9,6 @@ tests/cases/compiler/ambientStatement1.ts(4,20): error TS1039: Initializers are
99
!!! error TS1036: Statements are not allowed in ambient contexts.
1010

1111
export var v1 = () => false;
12-
~
12+
~~~~~~~~~~~
1313
!!! error TS1039: Initializers are not allowed in ambient contexts.
1414
}
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
1-
tests/cases/compiler/constDeclarations-ambient-errors.ts(2,27): error TS1039: Initializers are not allowed in ambient contexts.
2-
tests/cases/compiler/constDeclarations-ambient-errors.ts(3,26): error TS1039: Initializers are not allowed in ambient contexts.
1+
tests/cases/compiler/constDeclarations-ambient-errors.ts(2,29): error TS1039: Initializers are not allowed in ambient contexts.
2+
tests/cases/compiler/constDeclarations-ambient-errors.ts(3,28): error TS1039: Initializers are not allowed in ambient contexts.
33
tests/cases/compiler/constDeclarations-ambient-errors.ts(4,20): error TS1254: A 'const' initializer in an ambient context must be a string or numeric literal.
4-
tests/cases/compiler/constDeclarations-ambient-errors.ts(4,37): error TS1039: Initializers are not allowed in ambient contexts.
5-
tests/cases/compiler/constDeclarations-ambient-errors.ts(4,51): error TS1039: Initializers are not allowed in ambient contexts.
6-
tests/cases/compiler/constDeclarations-ambient-errors.ts(8,22): error TS1039: Initializers are not allowed in ambient contexts.
4+
tests/cases/compiler/constDeclarations-ambient-errors.ts(4,39): error TS1039: Initializers are not allowed in ambient contexts.
5+
tests/cases/compiler/constDeclarations-ambient-errors.ts(4,53): error TS1039: Initializers are not allowed in ambient contexts.
6+
tests/cases/compiler/constDeclarations-ambient-errors.ts(8,24): error TS1039: Initializers are not allowed in ambient contexts.
77

88

99
==== tests/cases/compiler/constDeclarations-ambient-errors.ts (6 errors) ====
1010
// error: no intialization expected in ambient declarations
1111
declare const c1: boolean = true;
12-
~
12+
~~~~
1313
!!! error TS1039: Initializers are not allowed in ambient contexts.
1414
declare const c2: number = 0;
15-
~
15+
~
1616
!!! error TS1039: Initializers are not allowed in ambient contexts.
1717
declare const c3 = null, c4 :string = "", c5: any = 0;
1818
~~~~
1919
!!! error TS1254: A 'const' initializer in an ambient context must be a string or numeric literal.
20-
~
20+
~~
2121
!!! error TS1039: Initializers are not allowed in ambient contexts.
22-
~
22+
~
2323
!!! error TS1039: Initializers are not allowed in ambient contexts.
2424

2525
declare module M {
2626
const c6 = 0;
2727
const c7: number = 7;
28-
~
28+
~
2929
!!! error TS1039: Initializers are not allowed in ambient contexts.
3030
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//// [declarationEmitConstantNoWidening.ts]
2+
export const FOO = 'FOO';
3+
export class Bar {
4+
readonly type = FOO; // Should be widening literal "FOO" - so either `typeof "FOO"` or = "FOO"
5+
}
6+
7+
//// [declarationEmitConstantNoWidening.js]
8+
"use strict";
9+
exports.__esModule = true;
10+
exports.FOO = 'FOO';
11+
var Bar = /** @class */ (function () {
12+
function Bar() {
13+
this.type = exports.FOO; // Should be widening literal "FOO" - so either `typeof "FOO"` or = "FOO"
14+
}
15+
return Bar;
16+
}());
17+
exports.Bar = Bar;
18+
19+
20+
//// [declarationEmitConstantNoWidening.d.ts]
21+
export declare const FOO = "FOO";
22+
export declare class Bar {
23+
readonly type = "FOO";
24+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
=== tests/cases/compiler/declarationEmitConstantNoWidening.ts ===
2+
export const FOO = 'FOO';
3+
>FOO : Symbol(FOO, Decl(declarationEmitConstantNoWidening.ts, 0, 12))
4+
5+
export class Bar {
6+
>Bar : Symbol(Bar, Decl(declarationEmitConstantNoWidening.ts, 0, 25))
7+
8+
readonly type = FOO; // Should be widening literal "FOO" - so either `typeof "FOO"` or = "FOO"
9+
>type : Symbol(Bar.type, Decl(declarationEmitConstantNoWidening.ts, 1, 18))
10+
>FOO : Symbol(FOO, Decl(declarationEmitConstantNoWidening.ts, 0, 12))
11+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
=== tests/cases/compiler/declarationEmitConstantNoWidening.ts ===
2+
export const FOO = 'FOO';
3+
>FOO : "FOO"
4+
>'FOO' : "FOO"
5+
6+
export class Bar {
7+
>Bar : Bar
8+
9+
readonly type = FOO; // Should be widening literal "FOO" - so either `typeof "FOO"` or = "FOO"
10+
>type : "FOO"
11+
>FOO : "FOO"
12+
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
tests/cases/compiler/externSemantics.ts(1,14): error TS1039: Initializers are not allowed in ambient contexts.
2-
tests/cases/compiler/externSemantics.ts(3,21): error TS1039: Initializers are not allowed in ambient contexts.
1+
tests/cases/compiler/externSemantics.ts(1,15): error TS1039: Initializers are not allowed in ambient contexts.
2+
tests/cases/compiler/externSemantics.ts(3,22): error TS1039: Initializers are not allowed in ambient contexts.
33

44

55
==== tests/cases/compiler/externSemantics.ts (2 errors) ====
66
declare var x=10;
7-
~
7+
~~
88
!!! error TS1039: Initializers are not allowed in ambient contexts.
99
declare var v;
1010
declare var y:number=3;
11-
~
11+
~
1212
!!! error TS1039: Initializers are not allowed in ambient contexts.
1313

0 commit comments

Comments
 (0)