From 1624e1bc1ae64dfe741ee55af5c5556cf3d100b1 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 19 Nov 2017 16:48:43 -0800 Subject: [PATCH 1/5] Definite assignment assertion '!' on variable and property declarations --- src/compiler/checker.ts | 14 +++++++++++++- src/compiler/diagnosticMessages.json | 4 ++++ src/compiler/parser.ts | 7 +++++++ src/compiler/types.ts | 12 ++++++++---- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dc1bab72c3..795fd199aa 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13121,8 +13121,10 @@ namespace ts { // the entire control flow graph from the variable's declaration (i.e. when the flow container and // declaration container are the same). const assumeInitialized = isParameter || isAlias || isOuterVariable || - type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) || + type !== autoType && type !== autoArrayType && (!strictNullChecks || (type.flags & TypeFlags.Any) !== 0 || + isInTypeQuery(node) || node.parent.kind === SyntaxKind.ExportSpecifier) || node.parent.kind === SyntaxKind.NonNullExpression || + declaration.kind === SyntaxKind.VariableDeclaration && (declaration).exclamationToken || declaration.flags & NodeFlags.Ambient; const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, getRootDeclaration(declaration) as VariableLikeDeclaration) : type) : type === autoType || type === autoArrayType ? undefinedType : @@ -22669,6 +22671,7 @@ namespace ts { function isInstancePropertyWithoutInitializer(node: Node) { return node.kind === SyntaxKind.PropertyDeclaration && !hasModifier(node, ModifierFlags.Static | ModifierFlags.Abstract) && + !(node).exclamationToken && !(node).initializer; } @@ -26101,6 +26104,10 @@ namespace ts { } } + if (node.exclamationToken && (node.parent.parent.kind !== SyntaxKind.VariableStatement || !node.type || node.initializer || node.flags & NodeFlags.Ambient)) { + return grammarErrorOnNode(node.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context); + } + if (compilerOptions.module !== ModuleKind.ES2015 && compilerOptions.module !== ModuleKind.ESNext && compilerOptions.module !== ModuleKind.System && !compilerOptions.noEmit && !(node.parent.parent.flags & NodeFlags.Ambient) && hasModifier(node.parent.parent, ModifierFlags.Export)) { checkESModuleMarker(node.name); @@ -26264,6 +26271,11 @@ namespace ts { if (node.flags & NodeFlags.Ambient && node.initializer) { return grammarErrorOnFirstToken(node.initializer, Diagnostics.Initializers_are_not_allowed_in_ambient_contexts); } + + if (node.exclamationToken && (!isClassLike(node.parent) || !node.type || node.initializer || + node.flags & NodeFlags.Ambient || hasModifier(node, ModifierFlags.Static | ModifierFlags.Abstract))) { + return grammarErrorOnNode(node.exclamationToken, Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context); + } } function checkGrammarTopLevelElementForRequiredDeclareModifier(node: Node): boolean { diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 7c0336cf60..09319589da 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -831,6 +831,10 @@ "category": "Error", "code": 1254 }, + "A definite assignment assertion '!' is not permitted in this context.": { + "category": "Error", + "code": 1255 + }, "'with' statements are not allowed in an async function block.": { "category": "Error", "code": 1300 diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index db2c09e34b..f9be81446f 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -99,6 +99,7 @@ namespace ts { visitNode(cbNode, (node).dotDotDotToken) || visitNode(cbNode, (node).name) || visitNode(cbNode, (node).questionToken) || + visitNode(cbNode, (node).exclamationToken) || visitNode(cbNode, (node).type) || visitNode(cbNode, (node).initializer); case SyntaxKind.FunctionType: @@ -5254,6 +5255,9 @@ namespace ts { function parseVariableDeclaration(): VariableDeclaration { const node = createNode(SyntaxKind.VariableDeclaration); node.name = parseIdentifierOrPattern(); + if (node.name.kind === SyntaxKind.Identifier && token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { + node.exclamationToken = parseTokenNode(); + } node.type = parseTypeAnnotation(); if (!isInOrOfKeyword(token())) { node.initializer = parseInitializer(); @@ -5346,6 +5350,9 @@ namespace ts { function parsePropertyDeclaration(node: PropertyDeclaration): PropertyDeclaration { node.kind = SyntaxKind.PropertyDeclaration; + if (!node.questionToken && token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { + node.exclamationToken = parseTokenNode(); + } node.type = parseTypeAnnotation(); // For instance properties specifically, since they are evaluated inside the constructor, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1ac7894b7a..53c36ac6ca 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -598,6 +598,7 @@ namespace ts { export type DotDotDotToken = Token; export type QuestionToken = Token; + export type ExclamationToken = Token; export type ColonToken = Token; export type EqualsToken = Token; export type AsteriskToken = Token; @@ -761,9 +762,10 @@ namespace ts { export interface VariableDeclaration extends NamedDeclaration { kind: SyntaxKind.VariableDeclaration; parent?: VariableDeclarationList | CatchClause; - name: BindingName; // Declared variable name - type?: TypeNode; // Optional type annotation - initializer?: Expression; // Optional initializer + name: BindingName; // Declared variable name + exclamationToken?: ExclamationToken; // Optional definite assignment assertion + type?: TypeNode; // Optional type annotation + initializer?: Expression; // Optional initializer } export interface VariableDeclarationList extends Node { @@ -801,8 +803,9 @@ namespace ts { export interface PropertyDeclaration extends ClassElement, JSDocContainer { kind: SyntaxKind.PropertyDeclaration; - questionToken?: QuestionToken; // Present for use with reporting a grammar error name: PropertyName; + questionToken?: QuestionToken; // Present for use with reporting a grammar error + exclamationToken?: ExclamationToken; type?: TypeNode; initializer?: Expression; // Optional initializer } @@ -860,6 +863,7 @@ namespace ts { dotDotDotToken?: DotDotDotToken; name: DeclarationName; questionToken?: QuestionToken; + exclamationToken?: ExclamationToken; type?: TypeNode; initializer?: Expression; } From 546663a59d26872b2b0cfa25017425770c7a326b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 19 Nov 2017 16:54:59 -0800 Subject: [PATCH 2/5] Accept new baselines --- tests/baselines/reference/api/tsserverlibrary.d.ts | 6 +++++- tests/baselines/reference/api/typescript.d.ts | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts index 319b29df2c..243ae3b7c6 100644 --- a/tests/baselines/reference/api/tsserverlibrary.d.ts +++ b/tests/baselines/reference/api/tsserverlibrary.d.ts @@ -461,6 +461,7 @@ declare namespace ts { } type DotDotDotToken = Token; type QuestionToken = Token; + type ExclamationToken = Token; type ColonToken = Token; type EqualsToken = Token; type AsteriskToken = Token; @@ -537,6 +538,7 @@ declare namespace ts { kind: SyntaxKind.VariableDeclaration; parent?: VariableDeclarationList | CatchClause; name: BindingName; + exclamationToken?: ExclamationToken; type?: TypeNode; initializer?: Expression; } @@ -571,8 +573,9 @@ declare namespace ts { } interface PropertyDeclaration extends ClassElement, JSDocContainer { kind: SyntaxKind.PropertyDeclaration; - questionToken?: QuestionToken; name: PropertyName; + questionToken?: QuestionToken; + exclamationToken?: ExclamationToken; type?: TypeNode; initializer?: Expression; } @@ -606,6 +609,7 @@ declare namespace ts { dotDotDotToken?: DotDotDotToken; name: DeclarationName; questionToken?: QuestionToken; + exclamationToken?: ExclamationToken; type?: TypeNode; initializer?: Expression; } diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts index c0cf5d5c54..6b2db71b14 100644 --- a/tests/baselines/reference/api/typescript.d.ts +++ b/tests/baselines/reference/api/typescript.d.ts @@ -461,6 +461,7 @@ declare namespace ts { } type DotDotDotToken = Token; type QuestionToken = Token; + type ExclamationToken = Token; type ColonToken = Token; type EqualsToken = Token; type AsteriskToken = Token; @@ -537,6 +538,7 @@ declare namespace ts { kind: SyntaxKind.VariableDeclaration; parent?: VariableDeclarationList | CatchClause; name: BindingName; + exclamationToken?: ExclamationToken; type?: TypeNode; initializer?: Expression; } @@ -571,8 +573,9 @@ declare namespace ts { } interface PropertyDeclaration extends ClassElement, JSDocContainer { kind: SyntaxKind.PropertyDeclaration; - questionToken?: QuestionToken; name: PropertyName; + questionToken?: QuestionToken; + exclamationToken?: ExclamationToken; type?: TypeNode; initializer?: Expression; } @@ -606,6 +609,7 @@ declare namespace ts { dotDotDotToken?: DotDotDotToken; name: DeclarationName; questionToken?: QuestionToken; + exclamationToken?: ExclamationToken; type?: TypeNode; initializer?: Expression; } From 272076391b53c4e0829f1c92f3c76a5f1977bb3b Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 20 Nov 2017 09:31:11 -0800 Subject: [PATCH 3/5] Allow '!' only on variable declarations within variable statements --- src/compiler/parser.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index f9be81446f..57129829ad 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -5252,10 +5252,15 @@ namespace ts { return parseIdentifier(); } - function parseVariableDeclaration(): VariableDeclaration { + function parseVariableDeclarationAllowExclamation() { + return parseVariableDeclaration(/*allowExclamation*/ true); + } + + function parseVariableDeclaration(allowExclamation?: boolean): VariableDeclaration { const node = createNode(SyntaxKind.VariableDeclaration); node.name = parseIdentifierOrPattern(); - if (node.name.kind === SyntaxKind.Identifier && token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { + if (allowExclamation && node.name.kind === SyntaxKind.Identifier && + token() === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) { node.exclamationToken = parseTokenNode(); } node.type = parseTypeAnnotation(); @@ -5299,7 +5304,8 @@ namespace ts { const savedDisallowIn = inDisallowInContext(); setDisallowInContext(inForStatementInitializer); - node.declarations = parseDelimitedList(ParsingContext.VariableDeclarations, parseVariableDeclaration); + node.declarations = parseDelimitedList(ParsingContext.VariableDeclarations, + inForStatementInitializer ? parseVariableDeclaration : parseVariableDeclarationAllowExclamation); setDisallowInContext(savedDisallowIn); } From 54d35b926ab19a29d85c2f8d5d59755e659d4557 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 20 Nov 2017 15:08:24 -0800 Subject: [PATCH 4/5] Add tests --- .../definiteAssignmentAssertions.ts | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts diff --git a/tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts b/tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts new file mode 100644 index 0000000000..b35c18d83c --- /dev/null +++ b/tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts @@ -0,0 +1,79 @@ +// @strict: true +// @declaration: true + +// Suppress strict property initialization check + +class C1 { + a!: number; + b: string; // Error +} + +// Suppress definite assignment check in constructor + +class C2 { + a!: number; + constructor() { + let x = this.a; + } +} + +// Definite assignment assertion requires type annotation, no initializer, no static modifier + +class C3 { + a! = 1; + b!: number = 1; + static c!: number; +} + +// Definite assignment assertion not permitted in ambient context + +declare class C4 { + a!: number; +} + +// Definite assignment assertion not permitted on abstract property + +abstract class C5 { + abstract a!: number; +} + +// Suppress definite assignment check for variable + +function f1() { + let x!: number; + let y = x; + var a!: number; + var b = a; +} + +function f2() { + let x!: string | number; + if (typeof x === "string") { + let s: string = x; + } + else { + let n: number = x; + } +} + +function f3() { + let x!: number; + const g = () => { + x = 1; + } + g(); + let y = x; +} + +// Definite assignment assertion requires type annotation and no initializer + +function f4() { + let a!; + let b! = 1; + let c!: number = 1; +} + +// Definite assignment assertion not permitted in ambient context + +declare let v1!: number; +declare var v2!: number; From 02fd11e3bd8b4d55711215309d0bca8ed471869c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 20 Nov 2017 15:08:33 -0800 Subject: [PATCH 5/5] Accept new baselines --- .../definiteAssignmentAssertions.errors.txt | 113 ++++++++++++ .../reference/definiteAssignmentAssertions.js | 166 ++++++++++++++++++ .../definiteAssignmentAssertions.symbols | 146 +++++++++++++++ .../definiteAssignmentAssertions.types | 157 +++++++++++++++++ 4 files changed, 582 insertions(+) create mode 100644 tests/baselines/reference/definiteAssignmentAssertions.errors.txt create mode 100644 tests/baselines/reference/definiteAssignmentAssertions.js create mode 100644 tests/baselines/reference/definiteAssignmentAssertions.symbols create mode 100644 tests/baselines/reference/definiteAssignmentAssertions.types diff --git a/tests/baselines/reference/definiteAssignmentAssertions.errors.txt b/tests/baselines/reference/definiteAssignmentAssertions.errors.txt new file mode 100644 index 0000000000..d65d9b510a --- /dev/null +++ b/tests/baselines/reference/definiteAssignmentAssertions.errors.txt @@ -0,0 +1,113 @@ +tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(5,5): error TS2564: Property 'b' has no initializer and is not definitely assigned in the constructor. +tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(20,6): error TS1255: A definite assignment assertion '!' is not permitted in this context. +tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(21,6): error TS1255: A definite assignment assertion '!' is not permitted in this context. +tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(22,13): error TS1255: A definite assignment assertion '!' is not permitted in this context. +tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(28,6): error TS1255: A definite assignment assertion '!' is not permitted in this context. +tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(34,15): error TS1255: A definite assignment assertion '!' is not permitted in this context. +tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(68,10): error TS1255: A definite assignment assertion '!' is not permitted in this context. +tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(69,10): error TS1255: A definite assignment assertion '!' is not permitted in this context. +tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(70,10): error TS1255: A definite assignment assertion '!' is not permitted in this context. +tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(75,15): error TS1255: A definite assignment assertion '!' is not permitted in this context. +tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(76,15): error TS1255: A definite assignment assertion '!' is not permitted in this context. + + +==== tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts (11 errors) ==== + // Suppress strict property initialization check + + class C1 { + a!: number; + b: string; // Error + ~ +!!! error TS2564: Property 'b' has no initializer and is not definitely assigned in the constructor. + } + + // Suppress definite assignment check in constructor + + class C2 { + a!: number; + constructor() { + let x = this.a; + } + } + + // Definite assignment assertion requires type annotation, no initializer, no static modifier + + class C3 { + a! = 1; + ~ +!!! error TS1255: A definite assignment assertion '!' is not permitted in this context. + b!: number = 1; + ~ +!!! error TS1255: A definite assignment assertion '!' is not permitted in this context. + static c!: number; + ~ +!!! error TS1255: A definite assignment assertion '!' is not permitted in this context. + } + + // Definite assignment assertion not permitted in ambient context + + declare class C4 { + a!: number; + ~ +!!! error TS1255: A definite assignment assertion '!' is not permitted in this context. + } + + // Definite assignment assertion not permitted on abstract property + + abstract class C5 { + abstract a!: number; + ~ +!!! error TS1255: A definite assignment assertion '!' is not permitted in this context. + } + + // Suppress definite assignment check for variable + + function f1() { + let x!: number; + let y = x; + var a!: number; + var b = a; + } + + function f2() { + let x!: string | number; + if (typeof x === "string") { + let s: string = x; + } + else { + let n: number = x; + } + } + + function f3() { + let x!: number; + const g = () => { + x = 1; + } + g(); + let y = x; + } + + // Definite assignment assertion requires type annotation and no initializer + + function f4() { + let a!; + ~ +!!! error TS1255: A definite assignment assertion '!' is not permitted in this context. + let b! = 1; + ~ +!!! error TS1255: A definite assignment assertion '!' is not permitted in this context. + let c!: number = 1; + ~ +!!! error TS1255: A definite assignment assertion '!' is not permitted in this context. + } + + // Definite assignment assertion not permitted in ambient context + + declare let v1!: number; + ~ +!!! error TS1255: A definite assignment assertion '!' is not permitted in this context. + declare var v2!: number; + ~ +!!! error TS1255: A definite assignment assertion '!' is not permitted in this context. + \ No newline at end of file diff --git a/tests/baselines/reference/definiteAssignmentAssertions.js b/tests/baselines/reference/definiteAssignmentAssertions.js new file mode 100644 index 0000000000..70bab1b9c2 --- /dev/null +++ b/tests/baselines/reference/definiteAssignmentAssertions.js @@ -0,0 +1,166 @@ +//// [definiteAssignmentAssertions.ts] +// Suppress strict property initialization check + +class C1 { + a!: number; + b: string; // Error +} + +// Suppress definite assignment check in constructor + +class C2 { + a!: number; + constructor() { + let x = this.a; + } +} + +// Definite assignment assertion requires type annotation, no initializer, no static modifier + +class C3 { + a! = 1; + b!: number = 1; + static c!: number; +} + +// Definite assignment assertion not permitted in ambient context + +declare class C4 { + a!: number; +} + +// Definite assignment assertion not permitted on abstract property + +abstract class C5 { + abstract a!: number; +} + +// Suppress definite assignment check for variable + +function f1() { + let x!: number; + let y = x; + var a!: number; + var b = a; +} + +function f2() { + let x!: string | number; + if (typeof x === "string") { + let s: string = x; + } + else { + let n: number = x; + } +} + +function f3() { + let x!: number; + const g = () => { + x = 1; + } + g(); + let y = x; +} + +// Definite assignment assertion requires type annotation and no initializer + +function f4() { + let a!; + let b! = 1; + let c!: number = 1; +} + +// Definite assignment assertion not permitted in ambient context + +declare let v1!: number; +declare var v2!: number; + + +//// [definiteAssignmentAssertions.js] +"use strict"; +// Suppress strict property initialization check +var C1 = /** @class */ (function () { + function C1() { + } + return C1; +}()); +// Suppress definite assignment check in constructor +var C2 = /** @class */ (function () { + function C2() { + var x = this.a; + } + return C2; +}()); +// Definite assignment assertion requires type annotation, no initializer, no static modifier +var C3 = /** @class */ (function () { + function C3() { + this.a = 1; + this.b = 1; + } + return C3; +}()); +// Definite assignment assertion not permitted on abstract property +var C5 = /** @class */ (function () { + function C5() { + } + return C5; +}()); +// Suppress definite assignment check for variable +function f1() { + var x; + var y = x; + var a; + var b = a; +} +function f2() { + var x; + if (typeof x === "string") { + var s = x; + } + else { + var n = x; + } +} +function f3() { + var x; + var g = function () { + x = 1; + }; + g(); + var y = x; +} +// Definite assignment assertion requires type annotation and no initializer +function f4() { + var a; + var b = 1; + var c = 1; +} + + +//// [definiteAssignmentAssertions.d.ts] +declare class C1 { + a: number; + b: string; +} +declare class C2 { + a: number; + constructor(); +} +declare class C3 { + a: number; + b: number; + static c: number; +} +declare class C4 { + a: number; +} +declare abstract class C5 { + abstract a: number; +} +declare function f1(): void; +declare function f2(): void; +declare function f3(): void; +declare function f4(): void; +declare let v1: number; +declare var v2: number; diff --git a/tests/baselines/reference/definiteAssignmentAssertions.symbols b/tests/baselines/reference/definiteAssignmentAssertions.symbols new file mode 100644 index 0000000000..a291172c83 --- /dev/null +++ b/tests/baselines/reference/definiteAssignmentAssertions.symbols @@ -0,0 +1,146 @@ +=== tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts === +// Suppress strict property initialization check + +class C1 { +>C1 : Symbol(C1, Decl(definiteAssignmentAssertions.ts, 0, 0)) + + a!: number; +>a : Symbol(C1.a, Decl(definiteAssignmentAssertions.ts, 2, 10)) + + b: string; // Error +>b : Symbol(C1.b, Decl(definiteAssignmentAssertions.ts, 3, 15)) +} + +// Suppress definite assignment check in constructor + +class C2 { +>C2 : Symbol(C2, Decl(definiteAssignmentAssertions.ts, 5, 1)) + + a!: number; +>a : Symbol(C2.a, Decl(definiteAssignmentAssertions.ts, 9, 10)) + + constructor() { + let x = this.a; +>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 12, 11)) +>this.a : Symbol(C2.a, Decl(definiteAssignmentAssertions.ts, 9, 10)) +>this : Symbol(C2, Decl(definiteAssignmentAssertions.ts, 5, 1)) +>a : Symbol(C2.a, Decl(definiteAssignmentAssertions.ts, 9, 10)) + } +} + +// Definite assignment assertion requires type annotation, no initializer, no static modifier + +class C3 { +>C3 : Symbol(C3, Decl(definiteAssignmentAssertions.ts, 14, 1)) + + a! = 1; +>a : Symbol(C3.a, Decl(definiteAssignmentAssertions.ts, 18, 10)) + + b!: number = 1; +>b : Symbol(C3.b, Decl(definiteAssignmentAssertions.ts, 19, 11)) + + static c!: number; +>c : Symbol(C3.c, Decl(definiteAssignmentAssertions.ts, 20, 19)) +} + +// Definite assignment assertion not permitted in ambient context + +declare class C4 { +>C4 : Symbol(C4, Decl(definiteAssignmentAssertions.ts, 22, 1)) + + a!: number; +>a : Symbol(C4.a, Decl(definiteAssignmentAssertions.ts, 26, 18)) +} + +// Definite assignment assertion not permitted on abstract property + +abstract class C5 { +>C5 : Symbol(C5, Decl(definiteAssignmentAssertions.ts, 28, 1)) + + abstract a!: number; +>a : Symbol(C5.a, Decl(definiteAssignmentAssertions.ts, 32, 19)) +} + +// Suppress definite assignment check for variable + +function f1() { +>f1 : Symbol(f1, Decl(definiteAssignmentAssertions.ts, 34, 1)) + + let x!: number; +>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 39, 7)) + + let y = x; +>y : Symbol(y, Decl(definiteAssignmentAssertions.ts, 40, 7)) +>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 39, 7)) + + var a!: number; +>a : Symbol(a, Decl(definiteAssignmentAssertions.ts, 41, 7)) + + var b = a; +>b : Symbol(b, Decl(definiteAssignmentAssertions.ts, 42, 7)) +>a : Symbol(a, Decl(definiteAssignmentAssertions.ts, 41, 7)) +} + +function f2() { +>f2 : Symbol(f2, Decl(definiteAssignmentAssertions.ts, 43, 1)) + + let x!: string | number; +>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 46, 7)) + + if (typeof x === "string") { +>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 46, 7)) + + let s: string = x; +>s : Symbol(s, Decl(definiteAssignmentAssertions.ts, 48, 11)) +>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 46, 7)) + } + else { + let n: number = x; +>n : Symbol(n, Decl(definiteAssignmentAssertions.ts, 51, 11)) +>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 46, 7)) + } +} + +function f3() { +>f3 : Symbol(f3, Decl(definiteAssignmentAssertions.ts, 53, 1)) + + let x!: number; +>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 56, 7)) + + const g = () => { +>g : Symbol(g, Decl(definiteAssignmentAssertions.ts, 57, 9)) + + x = 1; +>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 56, 7)) + } + g(); +>g : Symbol(g, Decl(definiteAssignmentAssertions.ts, 57, 9)) + + let y = x; +>y : Symbol(y, Decl(definiteAssignmentAssertions.ts, 61, 7)) +>x : Symbol(x, Decl(definiteAssignmentAssertions.ts, 56, 7)) +} + +// Definite assignment assertion requires type annotation and no initializer + +function f4() { +>f4 : Symbol(f4, Decl(definiteAssignmentAssertions.ts, 62, 1)) + + let a!; +>a : Symbol(a, Decl(definiteAssignmentAssertions.ts, 67, 7)) + + let b! = 1; +>b : Symbol(b, Decl(definiteAssignmentAssertions.ts, 68, 7)) + + let c!: number = 1; +>c : Symbol(c, Decl(definiteAssignmentAssertions.ts, 69, 7)) +} + +// Definite assignment assertion not permitted in ambient context + +declare let v1!: number; +>v1 : Symbol(v1, Decl(definiteAssignmentAssertions.ts, 74, 11)) + +declare var v2!: number; +>v2 : Symbol(v2, Decl(definiteAssignmentAssertions.ts, 75, 11)) + diff --git a/tests/baselines/reference/definiteAssignmentAssertions.types b/tests/baselines/reference/definiteAssignmentAssertions.types new file mode 100644 index 0000000000..92646bab86 --- /dev/null +++ b/tests/baselines/reference/definiteAssignmentAssertions.types @@ -0,0 +1,157 @@ +=== tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts === +// Suppress strict property initialization check + +class C1 { +>C1 : C1 + + a!: number; +>a : number + + b: string; // Error +>b : string +} + +// Suppress definite assignment check in constructor + +class C2 { +>C2 : C2 + + a!: number; +>a : number + + constructor() { + let x = this.a; +>x : number +>this.a : number +>this : this +>a : number + } +} + +// Definite assignment assertion requires type annotation, no initializer, no static modifier + +class C3 { +>C3 : C3 + + a! = 1; +>a : number +>1 : 1 + + b!: number = 1; +>b : number +>1 : 1 + + static c!: number; +>c : number +} + +// Definite assignment assertion not permitted in ambient context + +declare class C4 { +>C4 : C4 + + a!: number; +>a : number +} + +// Definite assignment assertion not permitted on abstract property + +abstract class C5 { +>C5 : C5 + + abstract a!: number; +>a : number +} + +// Suppress definite assignment check for variable + +function f1() { +>f1 : () => void + + let x!: number; +>x : number + + let y = x; +>y : number +>x : number + + var a!: number; +>a : number + + var b = a; +>b : number +>a : number +} + +function f2() { +>f2 : () => void + + let x!: string | number; +>x : string | number + + if (typeof x === "string") { +>typeof x === "string" : boolean +>typeof x : "string" | "number" | "boolean" | "symbol" | "undefined" | "object" | "function" +>x : string | number +>"string" : "string" + + let s: string = x; +>s : string +>x : string + } + else { + let n: number = x; +>n : number +>x : number + } +} + +function f3() { +>f3 : () => void + + let x!: number; +>x : number + + const g = () => { +>g : () => void +>() => { x = 1; } : () => void + + x = 1; +>x = 1 : 1 +>x : number +>1 : 1 + } + g(); +>g() : void +>g : () => void + + let y = x; +>y : number +>x : number +} + +// Definite assignment assertion requires type annotation and no initializer + +function f4() { +>f4 : () => void + + let a!; +>a : any + + let b! = 1; +>b : number +>1 : 1 + + let c!: number = 1; +>c : number +>1 : 1 +} + +// Definite assignment assertion not permitted in ambient context + +declare let v1!: number; +>v1 : number + +declare var v2!: number; +>v2 : number +