Skip to content

Commit 0310b53

Browse files
authored
feat(40663/40664): improve error messages for assignment assertions '!' (#40669)
1 parent 9c0eb22 commit 0310b53

8 files changed

+79
-48
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39485,11 +39485,13 @@ namespace ts {
3948539485
}
3948639486

3948739487
if (node.exclamationToken && (node.parent.parent.kind !== SyntaxKind.VariableStatement || !node.type || node.initializer || node.flags & NodeFlags.Ambient)) {
39488-
return grammarErrorOnNode(node.exclamationToken, Diagnostics.Definite_assignment_assertions_can_only_be_used_along_with_a_type_annotation);
39488+
const message = node.initializer
39489+
? Diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions
39490+
: Diagnostics.Definite_assignment_assertions_can_only_be_used_along_with_a_type_annotation;
39491+
return grammarErrorOnNode(node.exclamationToken, message);
3948939492
}
3949039493

3949139494
const moduleKind = getEmitModuleKind(compilerOptions);
39492-
3949339495
if (moduleKind < ModuleKind.ES2015 && moduleKind !== ModuleKind.System &&
3949439496
!(node.parent.parent.flags & NodeFlags.Ambient) && hasSyntacticModifier(node.parent.parent, ModifierFlags.Export)) {
3949539497
checkESModuleMarker(node.name);
@@ -39689,7 +39691,12 @@ namespace ts {
3968939691

3969039692
if (isPropertyDeclaration(node) && node.exclamationToken && (!isClassLike(node.parent) || !node.type || node.initializer ||
3969139693
node.flags & NodeFlags.Ambient || hasSyntacticModifier(node, ModifierFlags.Static | ModifierFlags.Abstract))) {
39692-
return grammarErrorOnNode(node.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context);
39694+
const message = node.initializer
39695+
? Diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions
39696+
: !node.type
39697+
? Diagnostics.Declarations_with_definite_assignment_assertions_must_also_have_type_annotations
39698+
: Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context;
39699+
return grammarErrorOnNode(node.exclamationToken, message);
3969339700
}
3969439701
}
3969539702

src/compiler/diagnosticMessages.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,14 @@
871871
"category": "Error",
872872
"code": 1262
873873
},
874+
"Declarations with initializers cannot also have definite assignment assertions.": {
875+
"category": "Error",
876+
"code": 1263
877+
},
878+
"Declarations with definite assignment assertions must also have type annotations.": {
879+
"category": "Error",
880+
"code": 1264
881+
},
874882

875883
"'with' statements are not allowed in an async function block.": {
876884
"category": "Error",

tests/baselines/reference/definiteAssignmentAssertions.errors.txt

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(5,5): error TS2564: Property 'b' has no initializer and is not definitely assigned in the constructor.
2-
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(20,6): error TS1255: A definite assignment assertion '!' is not permitted in this context.
3-
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(21,6): error TS1255: A definite assignment assertion '!' is not permitted in this context.
2+
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(20,6): error TS1263: Declarations with initializers cannot also have definite assignment assertions.
3+
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(21,6): error TS1263: Declarations with initializers cannot also have definite assignment assertions.
44
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(22,13): error TS1255: A definite assignment assertion '!' is not permitted in this context.
5-
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(28,6): error TS1255: A definite assignment assertion '!' is not permitted in this context.
6-
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(34,15): error TS1255: A definite assignment assertion '!' is not permitted in this context.
7-
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(68,10): error TS1258: Definite assignment assertions can only be used along with a type annotation.
5+
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(23,5): error TS7008: Member 'd' implicitly has an 'any' type.
6+
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(23,6): error TS1264: Declarations with definite assignment assertions must also have type annotations.
7+
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(29,6): error TS1255: A definite assignment assertion '!' is not permitted in this context.
8+
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(35,15): error TS1255: A definite assignment assertion '!' is not permitted in this context.
89
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(69,10): error TS1258: Definite assignment assertions can only be used along with a type annotation.
9-
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(70,10): error TS1258: Definite assignment assertions can only be used along with a type annotation.
10-
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(75,15): error TS1258: Definite assignment assertions can only be used along with a type annotation.
10+
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(70,10): error TS1263: Declarations with initializers cannot also have definite assignment assertions.
11+
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(71,10): error TS1263: Declarations with initializers cannot also have definite assignment assertions.
1112
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(76,15): error TS1258: Definite assignment assertions can only be used along with a type annotation.
13+
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(77,15): error TS1258: Definite assignment assertions can only be used along with a type annotation.
1214

1315

14-
==== tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts (11 errors) ====
16+
==== tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts (13 errors) ====
1517
// Suppress strict property initialization check
1618

1719
class C1 {
@@ -35,13 +37,18 @@ tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(76,15): erro
3537
class C3 {
3638
a! = 1;
3739
~
38-
!!! error TS1255: A definite assignment assertion '!' is not permitted in this context.
40+
!!! error TS1263: Declarations with initializers cannot also have definite assignment assertions.
3941
b!: number = 1;
4042
~
41-
!!! error TS1255: A definite assignment assertion '!' is not permitted in this context.
43+
!!! error TS1263: Declarations with initializers cannot also have definite assignment assertions.
4244
static c!: number;
4345
~
4446
!!! error TS1255: A definite assignment assertion '!' is not permitted in this context.
47+
d!;
48+
~
49+
!!! error TS7008: Member 'd' implicitly has an 'any' type.
50+
~
51+
!!! error TS1264: Declarations with definite assignment assertions must also have type annotations.
4552
}
4653

4754
// Definite assignment assertion not permitted in ambient context
@@ -96,10 +103,10 @@ tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(76,15): erro
96103
!!! error TS1258: Definite assignment assertions can only be used along with a type annotation.
97104
let b! = 1;
98105
~
99-
!!! error TS1258: Definite assignment assertions can only be used along with a type annotation.
106+
!!! error TS1263: Declarations with initializers cannot also have definite assignment assertions.
100107
let c!: number = 1;
101108
~
102-
!!! error TS1258: Definite assignment assertions can only be used along with a type annotation.
109+
!!! error TS1263: Declarations with initializers cannot also have definite assignment assertions.
103110
}
104111

105112
// Definite assignment assertion not permitted in ambient context

tests/baselines/reference/definiteAssignmentAssertions.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ class C3 {
2121
a! = 1;
2222
b!: number = 1;
2323
static c!: number;
24+
d!;
2425
}
2526

2627
// Definite assignment assertion not permitted in ambient context
@@ -151,6 +152,7 @@ declare class C3 {
151152
a: number;
152153
b: number;
153154
static c: number;
155+
d: any;
154156
}
155157
declare class C4 {
156158
a: number;

tests/baselines/reference/definiteAssignmentAssertions.symbols

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -41,106 +41,109 @@ class C3 {
4141

4242
static c!: number;
4343
>c : Symbol(C3.c, Decl(definiteAssignmentAssertions.ts, 20, 19))
44+
45+
d!;
46+
>d : Symbol(C3.d, Decl(definiteAssignmentAssertions.ts, 21, 22))
4447
}
4548

4649
// Definite assignment assertion not permitted in ambient context
4750

4851
declare class C4 {
49-
>C4 : Symbol(C4, Decl(definiteAssignmentAssertions.ts, 22, 1))
52+
>C4 : Symbol(C4, Decl(definiteAssignmentAssertions.ts, 23, 1))
5053

5154
a!: number;
52-
>a : Symbol(C4.a, Decl(definiteAssignmentAssertions.ts, 26, 18))
55+
>a : Symbol(C4.a, Decl(definiteAssignmentAssertions.ts, 27, 18))
5356
}
5457

5558
// Definite assignment assertion not permitted on abstract property
5659

5760
abstract class C5 {
58-
>C5 : Symbol(C5, Decl(definiteAssignmentAssertions.ts, 28, 1))
61+
>C5 : Symbol(C5, Decl(definiteAssignmentAssertions.ts, 29, 1))
5962

6063
abstract a!: number;
61-
>a : Symbol(C5.a, Decl(definiteAssignmentAssertions.ts, 32, 19))
64+
>a : Symbol(C5.a, Decl(definiteAssignmentAssertions.ts, 33, 19))
6265
}
6366

6467
// Suppress definite assignment check for variable
6568

6669
function f1() {
67-
>f1 : Symbol(f1, Decl(definiteAssignmentAssertions.ts, 34, 1))
70+
>f1 : Symbol(f1, Decl(definiteAssignmentAssertions.ts, 35, 1))
6871

6972
let x!: number;
70-
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 39, 7))
73+
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 40, 7))
7174

7275
let y = x;
73-
>y : Symbol(y, Decl(definiteAssignmentAssertions.ts, 40, 7))
74-
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 39, 7))
76+
>y : Symbol(y, Decl(definiteAssignmentAssertions.ts, 41, 7))
77+
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 40, 7))
7578

7679
var a!: number;
77-
>a : Symbol(a, Decl(definiteAssignmentAssertions.ts, 41, 7))
80+
>a : Symbol(a, Decl(definiteAssignmentAssertions.ts, 42, 7))
7881

7982
var b = a;
80-
>b : Symbol(b, Decl(definiteAssignmentAssertions.ts, 42, 7))
81-
>a : Symbol(a, Decl(definiteAssignmentAssertions.ts, 41, 7))
83+
>b : Symbol(b, Decl(definiteAssignmentAssertions.ts, 43, 7))
84+
>a : Symbol(a, Decl(definiteAssignmentAssertions.ts, 42, 7))
8285
}
8386

8487
function f2() {
85-
>f2 : Symbol(f2, Decl(definiteAssignmentAssertions.ts, 43, 1))
88+
>f2 : Symbol(f2, Decl(definiteAssignmentAssertions.ts, 44, 1))
8689

8790
let x!: string | number;
88-
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 46, 7))
91+
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 47, 7))
8992

9093
if (typeof x === "string") {
91-
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 46, 7))
94+
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 47, 7))
9295

9396
let s: string = x;
94-
>s : Symbol(s, Decl(definiteAssignmentAssertions.ts, 48, 11))
95-
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 46, 7))
97+
>s : Symbol(s, Decl(definiteAssignmentAssertions.ts, 49, 11))
98+
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 47, 7))
9699
}
97100
else {
98101
let n: number = x;
99-
>n : Symbol(n, Decl(definiteAssignmentAssertions.ts, 51, 11))
100-
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 46, 7))
102+
>n : Symbol(n, Decl(definiteAssignmentAssertions.ts, 52, 11))
103+
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 47, 7))
101104
}
102105
}
103106

104107
function f3() {
105-
>f3 : Symbol(f3, Decl(definiteAssignmentAssertions.ts, 53, 1))
108+
>f3 : Symbol(f3, Decl(definiteAssignmentAssertions.ts, 54, 1))
106109

107110
let x!: number;
108-
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 56, 7))
111+
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 57, 7))
109112

110113
const g = () => {
111-
>g : Symbol(g, Decl(definiteAssignmentAssertions.ts, 57, 9))
114+
>g : Symbol(g, Decl(definiteAssignmentAssertions.ts, 58, 9))
112115

113116
x = 1;
114-
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 56, 7))
117+
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 57, 7))
115118
}
116119
g();
117-
>g : Symbol(g, Decl(definiteAssignmentAssertions.ts, 57, 9))
120+
>g : Symbol(g, Decl(definiteAssignmentAssertions.ts, 58, 9))
118121

119122
let y = x;
120-
>y : Symbol(y, Decl(definiteAssignmentAssertions.ts, 61, 7))
121-
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 56, 7))
123+
>y : Symbol(y, Decl(definiteAssignmentAssertions.ts, 62, 7))
124+
>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 57, 7))
122125
}
123126

124127
// Definite assignment assertion requires type annotation and no initializer
125128

126129
function f4() {
127-
>f4 : Symbol(f4, Decl(definiteAssignmentAssertions.ts, 62, 1))
130+
>f4 : Symbol(f4, Decl(definiteAssignmentAssertions.ts, 63, 1))
128131

129132
let a!;
130-
>a : Symbol(a, Decl(definiteAssignmentAssertions.ts, 67, 7))
133+
>a : Symbol(a, Decl(definiteAssignmentAssertions.ts, 68, 7))
131134

132135
let b! = 1;
133-
>b : Symbol(b, Decl(definiteAssignmentAssertions.ts, 68, 7))
136+
>b : Symbol(b, Decl(definiteAssignmentAssertions.ts, 69, 7))
134137

135138
let c!: number = 1;
136-
>c : Symbol(c, Decl(definiteAssignmentAssertions.ts, 69, 7))
139+
>c : Symbol(c, Decl(definiteAssignmentAssertions.ts, 70, 7))
137140
}
138141

139142
// Definite assignment assertion not permitted in ambient context
140143

141144
declare let v1!: number;
142-
>v1 : Symbol(v1, Decl(definiteAssignmentAssertions.ts, 74, 11))
145+
>v1 : Symbol(v1, Decl(definiteAssignmentAssertions.ts, 75, 11))
143146

144147
declare var v2!: number;
145-
>v2 : Symbol(v2, Decl(definiteAssignmentAssertions.ts, 75, 11))
148+
>v2 : Symbol(v2, Decl(definiteAssignmentAssertions.ts, 76, 11))
146149

tests/baselines/reference/definiteAssignmentAssertions.types

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ class C3 {
4343

4444
static c!: number;
4545
>c : number
46+
47+
d!;
48+
>d : any
4649
}
4750

4851
// Definite assignment assertion not permitted in ambient context
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
tests/cases/compiler/definiteAssignmentWithErrorStillStripped.ts(2,6): error TS1255: A definite assignment assertion '!' is not permitted in this context.
1+
tests/cases/compiler/definiteAssignmentWithErrorStillStripped.ts(2,6): error TS1264: Declarations with definite assignment assertions must also have type annotations.
22

33

44
==== tests/cases/compiler/definiteAssignmentWithErrorStillStripped.ts (1 errors) ====
55
class C {
66
p!;
77
~
8-
!!! error TS1255: A definite assignment assertion '!' is not permitted in this context.
8+
!!! error TS1264: Declarations with definite assignment assertions must also have type annotations.
99
}

tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class C3 {
2323
a! = 1;
2424
b!: number = 1;
2525
static c!: number;
26+
d!;
2627
}
2728

2829
// Definite assignment assertion not permitted in ambient context

0 commit comments

Comments
 (0)