Skip to content

Commit 614a07c

Browse files
authored
Fix printing and emit for definite assignment assertions (#35095)
* Fix printing and emit for definite assignment assertions * Make factories that handle definite assertions internal
1 parent a6d44aa commit 614a07c

File tree

7 files changed

+42
-3
lines changed

7 files changed

+42
-3
lines changed

src/compiler/binder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3807,7 +3807,7 @@ namespace ts {
38073807
}
38083808

38093809
// Type annotations are TypeScript syntax.
3810-
if (node.type) {
3810+
if (node.type || node.exclamationToken) {
38113811
transformFlags |= TransformFlags.AssertTypeScript;
38123812
}
38133813

src/compiler/emitter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2741,6 +2741,7 @@ namespace ts {
27412741

27422742
function emitVariableDeclaration(node: VariableDeclaration) {
27432743
emit(node.name);
2744+
emit(node.exclamationToken);
27442745
emitTypeAnnotation(node.type);
27452746
emitInitializer(node.initializer, node.type ? node.type.end : node.name.end, node);
27462747
}

src/compiler/factory.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1937,6 +1937,7 @@ namespace ts {
19371937
}
19381938

19391939
export function createVariableDeclaration(name: string | BindingName, type?: TypeNode, initializer?: Expression) {
1940+
/* Internally, one should probably use createTypeScriptVariableDeclaration instead and handle definite assignment assertions */
19401941
const node = <VariableDeclaration>createSynthesizedNode(SyntaxKind.VariableDeclaration);
19411942
node.name = asName(name);
19421943
node.type = type;
@@ -1945,13 +1946,34 @@ namespace ts {
19451946
}
19461947

19471948
export function updateVariableDeclaration(node: VariableDeclaration, name: BindingName, type: TypeNode | undefined, initializer: Expression | undefined) {
1949+
/* Internally, one should probably use updateTypeScriptVariableDeclaration instead and handle definite assignment assertions */
19481950
return node.name !== name
19491951
|| node.type !== type
19501952
|| node.initializer !== initializer
19511953
? updateNode(createVariableDeclaration(name, type, initializer), node)
19521954
: node;
19531955
}
19541956

1957+
/* @internal */
1958+
export function createTypeScriptVariableDeclaration(name: string | BindingName, exclaimationToken?: Token<SyntaxKind.ExclamationToken>, type?: TypeNode, initializer?: Expression) {
1959+
const node = <VariableDeclaration>createSynthesizedNode(SyntaxKind.VariableDeclaration);
1960+
node.name = asName(name);
1961+
node.type = type;
1962+
node.initializer = initializer !== undefined ? parenthesizeExpressionForList(initializer) : undefined;
1963+
node.exclamationToken = exclaimationToken;
1964+
return node;
1965+
}
1966+
1967+
/* @internal */
1968+
export function updateTypeScriptVariableDeclaration(node: VariableDeclaration, name: BindingName, exclaimationToken: Token<SyntaxKind.ExclamationToken> | undefined, type: TypeNode | undefined, initializer: Expression | undefined) {
1969+
return node.name !== name
1970+
|| node.type !== type
1971+
|| node.initializer !== initializer
1972+
|| node.exclamationToken !== exclaimationToken
1973+
? updateNode(createTypeScriptVariableDeclaration(name, exclaimationToken, type, initializer), node)
1974+
: node;
1975+
}
1976+
19551977
export function createVariableDeclarationList(declarations: readonly VariableDeclaration[], flags = NodeFlags.None) {
19561978
const node = <VariableDeclarationList>createSynthesizedNode(SyntaxKind.VariableDeclarationList);
19571979
node.flags |= flags & NodeFlags.BlockScoped;

src/compiler/transformers/declarations.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -937,7 +937,7 @@ namespace ts {
937937
}
938938
shouldEnterSuppressNewDiagnosticsContextContext = true;
939939
suppressNewDiagnosticContexts = true; // Variable declaration types also suppress new diagnostic contexts, provided the contexts wouldn't be made for binding pattern types
940-
return cleanup(updateVariableDeclaration(input, input.name, ensureType(input, input.type), ensureNoInitializer(input)));
940+
return cleanup(updateTypeScriptVariableDeclaration(input, input.name, /*exclaimationToken*/ undefined, ensureType(input, input.type), ensureNoInitializer(input)));
941941
}
942942
case SyntaxKind.TypeParameter: {
943943
if (isPrivateMethodTypeParameter(input) && (input.default || input.constraint)) {

src/compiler/transformers/ts.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2188,9 +2188,10 @@ namespace ts {
21882188
}
21892189

21902190
function visitVariableDeclaration(node: VariableDeclaration) {
2191-
return updateVariableDeclaration(
2191+
return updateTypeScriptVariableDeclaration(
21922192
node,
21932193
visitNode(node.name, visitor, isBindingName),
2194+
/*exclaimationToken*/ undefined,
21942195
/*type*/ undefined,
21952196
visitNode(node.initializer, visitor, isExpression));
21962197
}

src/testRunner/unittests/printer.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,17 @@ namespace ts {
6767
`class A extends B implements C implements D {}`,
6868
ScriptTarget.ES2017
6969
)));
70+
71+
// github #35093
72+
printsCorrectly("definiteAssignmentAssertions", {}, printer => printer.printFile(createSourceFile(
73+
"source.ts",
74+
`class A {
75+
prop!: string;
76+
}
77+
78+
let x!: string;`,
79+
ScriptTarget.ES2017
80+
)));
7081
});
7182

7283
describe("printBundle", () => {
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class A {
2+
prop!: string;
3+
}
4+
let x!: string;

0 commit comments

Comments
 (0)