diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3cd33b923f0..bb7f8d013fc 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -15889,7 +15889,7 @@ namespace ts { // Referencing abstract properties within their own constructors is not allowed if ((flags & ModifierFlags.Abstract) && isThisProperty(node) && symbolHasNonMethodDeclaration(prop)) { - const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)); + const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)); if (declaringClassDeclaration && isNodeWithinConstructorOfClass(node, declaringClassDeclaration)) { error(errorNode, Diagnostics.Abstract_property_0_in_class_1_cannot_be_accessed_in_the_constructor, symbolToString(prop), getTextOfIdentifierOrLiteral(declaringClassDeclaration.name)); return false; @@ -15905,7 +15905,7 @@ namespace ts { // Private property is accessible if the property is within the declaring class if (flags & ModifierFlags.Private) { - const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)); + const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(getParentOfSymbol(prop)); if (!isNodeWithinClass(node, declaringClassDeclaration)) { error(errorNode, Diagnostics.Property_0_is_private_and_only_accessible_within_class_1, symbolToString(prop), typeToString(getDeclaringClass(prop))); return false; @@ -17627,7 +17627,7 @@ namespace ts { return true; } - const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(declaration.parent.symbol); + const declaringClassDeclaration = getClassLikeDeclarationOfSymbol(declaration.parent.symbol); const declaringClass = getDeclaredTypeOfSymbol(declaration.parent.symbol); // A private or protected constructor can only be instantiated within its own class (or a subclass, for protected) @@ -23115,7 +23115,7 @@ namespace ts { if (signatures.length) { const declaration = signatures[0].declaration; if (declaration && hasModifier(declaration, ModifierFlags.Private)) { - const typeClassDeclaration = getClassLikeDeclarationOfSymbol(type.symbol); + const typeClassDeclaration = getClassLikeDeclarationOfSymbol(type.symbol); if (!isNodeWithinClass(node, typeClassDeclaration)) { error(node, Diagnostics.Cannot_extend_a_class_0_Class_constructor_is_marked_as_private, getFullyQualifiedName(type.symbol)); } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index f120e81283a..9801da54a5f 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -3965,5 +3965,17 @@ "Convert to ES6 module": { "category": "Message", "code": 95017 + }, + "Add 'undefined' type to property '{0}'": { + "category": "Message", + "code": 95018 + }, + "Add initializer to property '{0}'": { + "category": "Message", + "code": 95019 + }, + "Add definite assignment assertion to property '{0}'": { + "category": "Message", + "code": 95020 } } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index df1394efd00..3fa05950b23 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -1024,6 +1024,7 @@ namespace ts { emitModifiers(node, node.modifiers); emit(node.name); emitIfPresent(node.questionToken); + emitIfPresent(node.exclamationToken); emitTypeAnnotation(node.type); emitInitializer(node.initializer); writeSemicolon(); diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 863e8107f33..d8ee9f3dbf0 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3738,7 +3738,7 @@ namespace ts { return false; } - export function getClassLikeDeclarationOfSymbol(symbol: Symbol): Declaration | undefined { + export function getClassLikeDeclarationOfSymbol(symbol: Symbol): ClassLikeDeclaration | undefined { return find(symbol.declarations, isClassLike); } diff --git a/src/services/codefixes/fixStrictClassInitialization.ts b/src/services/codefixes/fixStrictClassInitialization.ts new file mode 100644 index 00000000000..1199e6a059d --- /dev/null +++ b/src/services/codefixes/fixStrictClassInitialization.ts @@ -0,0 +1,142 @@ +/* @internal */ +namespace ts.codefix { + const fixIdAddDefiniteAssignmentAssertions = "addMissingPropertyDefiniteAssignmentAssertions"; + const fixIdAddUndefinedType = "addMissingPropertyUndefinedType"; + const fixIdAddInitializer = "addMissingPropertyInitializer"; + const errorCodes = [Diagnostics.Property_0_has_no_initializer_and_is_not_definitely_assigned_in_the_constructor.code]; + registerCodeFix({ + errorCodes, + getCodeActions: (context) => { + const propertyDeclaration = getPropertyDeclaration(context.sourceFile, context.span.start); + if (!propertyDeclaration) return; + + const newLineCharacter = getNewLineOrDefaultFromHost(context.host, context.formatContext.options); + const result = [ + getActionForAddMissingUndefinedType(context, propertyDeclaration), + getActionForAddMissingDefiniteAssignmentAssertion(context, propertyDeclaration, newLineCharacter) + ]; + + append(result, getActionForAddMissingInitializer(context, propertyDeclaration, newLineCharacter)); + + return result; + }, + fixIds: [fixIdAddDefiniteAssignmentAssertions, fixIdAddUndefinedType, fixIdAddInitializer], + getAllCodeActions: context => { + const newLineCharacter = getNewLineOrDefaultFromHost(context.host, context.formatContext.options); + + return codeFixAll(context, errorCodes, (changes, diag) => { + const propertyDeclaration = getPropertyDeclaration(diag.file, diag.start); + if (!propertyDeclaration) return; + + switch (context.fixId) { + case fixIdAddDefiniteAssignmentAssertions: + addDefiniteAssignmentAssertion(changes, diag.file, propertyDeclaration, newLineCharacter); + break; + case fixIdAddUndefinedType: + addUndefinedType(changes, diag.file, propertyDeclaration); + break; + case fixIdAddInitializer: + const checker = context.program.getTypeChecker(); + const initializer = getInitializer(checker, propertyDeclaration); + if (!initializer) return; + + addInitializer(changes, diag.file, propertyDeclaration, initializer, newLineCharacter); + break; + default: + Debug.fail(JSON.stringify(context.fixId)); + } + }); + }, + }); + + function getPropertyDeclaration (sourceFile: SourceFile, pos: number): PropertyDeclaration | undefined { + const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false); + return isIdentifier(token) ? cast(token.parent, isPropertyDeclaration) : undefined; + } + + function getActionForAddMissingDefiniteAssignmentAssertion (context: CodeFixContext, propertyDeclaration: PropertyDeclaration, newLineCharacter: string): CodeFixAction { + const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_definite_assignment_assertion_to_property_0), [propertyDeclaration.getText()]); + const changes = textChanges.ChangeTracker.with(context, t => addDefiniteAssignmentAssertion(t, context.sourceFile, propertyDeclaration, newLineCharacter)); + return { description, changes, fixId: fixIdAddDefiniteAssignmentAssertions }; + } + + function addDefiniteAssignmentAssertion(changeTracker: textChanges.ChangeTracker, propertyDeclarationSourceFile: SourceFile, propertyDeclaration: PropertyDeclaration, newLineCharacter: string): void { + const property = updateProperty( + propertyDeclaration, + propertyDeclaration.decorators, + propertyDeclaration.modifiers, + propertyDeclaration.name, + createToken(SyntaxKind.ExclamationToken), + propertyDeclaration.type, + propertyDeclaration.initializer + ); + changeTracker.replaceNode(propertyDeclarationSourceFile, propertyDeclaration, property, { suffix: newLineCharacter }); + } + + function getActionForAddMissingUndefinedType (context: CodeFixContext, propertyDeclaration: PropertyDeclaration): CodeFixAction { + const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_undefined_type_to_property_0), [propertyDeclaration.name.getText()]); + const changes = textChanges.ChangeTracker.with(context, t => addUndefinedType(t, context.sourceFile, propertyDeclaration)); + return { description, changes, fixId: fixIdAddUndefinedType }; + } + + function addUndefinedType(changeTracker: textChanges.ChangeTracker, propertyDeclarationSourceFile: SourceFile, propertyDeclaration: PropertyDeclaration): void { + const undefinedTypeNode = createKeywordTypeNode(SyntaxKind.UndefinedKeyword); + const types = isUnionTypeNode(propertyDeclaration.type) ? propertyDeclaration.type.types.concat(undefinedTypeNode) : [propertyDeclaration.type, undefinedTypeNode]; + changeTracker.replaceNode(propertyDeclarationSourceFile, propertyDeclaration.type, createUnionTypeNode(types)); + } + + function getActionForAddMissingInitializer (context: CodeFixContext, propertyDeclaration: PropertyDeclaration, newLineCharacter: string): CodeFixAction | undefined { + const checker = context.program.getTypeChecker(); + const initializer = getInitializer(checker, propertyDeclaration); + if (!initializer) return undefined; + + const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_initializer_to_property_0), [propertyDeclaration.name.getText()]); + const changes = textChanges.ChangeTracker.with(context, t => addInitializer(t, context.sourceFile, propertyDeclaration, initializer, newLineCharacter)); + return { description, changes, fixId: fixIdAddInitializer }; + } + + function addInitializer (changeTracker: textChanges.ChangeTracker, propertyDeclarationSourceFile: SourceFile, propertyDeclaration: PropertyDeclaration, initializer: Expression, newLineCharacter: string): void { + const property = updateProperty( + propertyDeclaration, + propertyDeclaration.decorators, + propertyDeclaration.modifiers, + propertyDeclaration.name, + propertyDeclaration.questionToken, + propertyDeclaration.type, + initializer + ); + changeTracker.replaceNode(propertyDeclarationSourceFile, propertyDeclaration, property, { suffix: newLineCharacter }); + } + + function getInitializer(checker: TypeChecker, propertyDeclaration: PropertyDeclaration): Expression | undefined { + return getDefaultValueFromType(checker, checker.getTypeFromTypeNode(propertyDeclaration.type)); + } + + function getDefaultValueFromType (checker: TypeChecker, type: Type): Expression | undefined { + if (type.flags & TypeFlags.String) { + return createLiteral(""); + } + else if (type.flags & TypeFlags.Number) { + return createNumericLiteral("0"); + } + else if (type.flags & TypeFlags.Boolean) { + return createFalse(); + } + else if (type.flags & TypeFlags.Literal) { + return createLiteral((type).value); + } + else if (type.flags & TypeFlags.Union) { + return firstDefined((type).types, t => getDefaultValueFromType(checker, t)); + } + else if (getObjectFlags(type) & ObjectFlags.Class) { + const classDeclaration = getClassLikeDeclarationOfSymbol(type.symbol); + if (!classDeclaration || hasModifier(classDeclaration, ModifierFlags.Abstract)) return undefined; + + const constructorDeclaration = find(classDeclaration.members, (m): m is ConstructorDeclaration => isConstructorDeclaration(m) && !!m.body)!; + if (constructorDeclaration && constructorDeclaration.parameters.length) return undefined; + + return createNew(createIdentifier(type.symbol.name), /*typeArguments*/ undefined, /*argumentsArray*/ undefined); + } + return undefined; + } +} diff --git a/src/services/codefixes/fixes.ts b/src/services/codefixes/fixes.ts index 317c65b15ee..671f2251a32 100644 --- a/src/services/codefixes/fixes.ts +++ b/src/services/codefixes/fixes.ts @@ -17,4 +17,4 @@ /// /// /// - +/// diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization.ts new file mode 100644 index 00000000000..224d7dd17b9 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization.ts @@ -0,0 +1,40 @@ +/// + +// @strict: true + +//// abstract class A { abstract a (); } +//// +//// class TT { constructor () {} } +//// +//// class AT extends A { a () {} } +//// +//// class Foo {} +//// +//// class T { +//// +//// a: string; +//// +//// static b: string; +//// +//// private c: string; +//// +//// d: number | undefined; +//// +//// e: string | number; +//// +//// f: 1; +//// +//// g: "123" | "456"; +//// +//// h: boolean; +//// +//// i: TT; +//// +//// j: A; +//// +//// k: AT; +//// +//// l: Foo; +//// } + +verify.codeFixAvailable() \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization1.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization1.ts new file mode 100644 index 00000000000..ed3f4c409f9 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization1.ts @@ -0,0 +1,15 @@ +/// + +// @strict: true + +//// class T { +//// a: string; +//// } + +verify.codeFix({ + description: `Add 'undefined' type to property 'a'`, + newFileContent: `class T { + a: string | undefined; +}`, + index: 0 +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization10.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization10.ts new file mode 100644 index 00000000000..52c290d3f02 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization10.ts @@ -0,0 +1,15 @@ +/// + +// @strict: true + +//// class T { +//// a: "a" | 2; +//// } + +verify.codeFix({ + description: `Add initializer to property 'a'`, + newFileContent: `class T { + a: "a" | 2 = "a"; +}`, + index: 2 +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization11.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization11.ts new file mode 100644 index 00000000000..d924a03ec01 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization11.ts @@ -0,0 +1,19 @@ +/// + +// @strict: true + +//// class TT { constructor () {} } +//// +//// class T { +//// a: TT; +//// } + +verify.codeFix({ + description: `Add initializer to property 'a'`, + newFileContent: `class TT { constructor () {} } + +class T { + a: TT = new TT; +}`, + index: 2 +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization12.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization12.ts new file mode 100644 index 00000000000..5463786415c --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization12.ts @@ -0,0 +1,23 @@ +/// + +// @strict: true + +//// abstract class A { abstract a (); } +//// +//// class AT extends A { a () {} } +//// +//// class T { +//// a: AT; +//// } + +verify.codeFix({ + description: `Add initializer to property 'a'`, + newFileContent: `abstract class A { abstract a (); } + +class AT extends A { a () {} } + +class T { + a: AT = new AT; +}`, + index: 2 +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization13.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization13.ts new file mode 100644 index 00000000000..e4aec8184ef --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization13.ts @@ -0,0 +1,19 @@ +/// + +// @strict: true + +//// class TT { } +//// +//// class T { +//// a: TT; +//// } + +verify.codeFix({ + description: `Add initializer to property 'a'`, + newFileContent: `class TT { } + +class T { + a: TT = new TT; +}`, + index: 2 +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization2.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization2.ts new file mode 100644 index 00000000000..93313babd81 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization2.ts @@ -0,0 +1,15 @@ +/// + +// @strict: true + +//// class T { +//// a: string; +//// } + +verify.codeFix({ + description: `Add definite assignment assertion to property 'a: string;'`, + newFileContent: `class T { + a!: string; +}`, + index: 1 +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization3.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization3.ts new file mode 100644 index 00000000000..329c6107ac7 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization3.ts @@ -0,0 +1,15 @@ +/// + +// @strict: true + +//// class T { +//// a: string; +//// } + +verify.codeFix({ + description: `Add initializer to property 'a'`, + newFileContent: `class T { + a: string = ""; +}`, + index: 2 +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization4.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization4.ts new file mode 100644 index 00000000000..17a363e15b3 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization4.ts @@ -0,0 +1,15 @@ +/// + +// @strict: true + +//// class T { +//// a: number; +//// } + +verify.codeFix({ + description: `Add initializer to property 'a'`, + newFileContent: `class T { + a: number = 0; +}`, + index: 2 +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization5.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization5.ts new file mode 100644 index 00000000000..8b76da581fe --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization5.ts @@ -0,0 +1,15 @@ +/// + +// @strict: true + +//// class T { +//// a: boolean; +//// } + +verify.codeFix({ + description: `Add initializer to property 'a'`, + newFileContent: `class T { + a: boolean = false; +}`, + index: 2 +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization6.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization6.ts new file mode 100644 index 00000000000..b86bfb11eba --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization6.ts @@ -0,0 +1,15 @@ +/// + +// @strict: true + +//// class T { +//// a: "1"; +//// } + +verify.codeFix({ + description: `Add initializer to property 'a'`, + newFileContent: `class T { + a: "1" = "1"; +}`, + index: 2 +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization7.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization7.ts new file mode 100644 index 00000000000..065eb10b301 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization7.ts @@ -0,0 +1,15 @@ +/// + +// @strict: true + +//// class T { +//// a: 2; +//// } + +verify.codeFix({ + description: `Add initializer to property 'a'`, + newFileContent: `class T { + a: 2 = 2; +}`, + index: 2 +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization8.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization8.ts new file mode 100644 index 00000000000..5c1f7873c16 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization8.ts @@ -0,0 +1,15 @@ +/// + +// @strict: true + +//// class T { +//// a: string | number; +//// } + +verify.codeFix({ + description: `Add initializer to property 'a'`, + newFileContent: `class T { + a: string | number = ""; +}`, + index: 2 +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization9.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization9.ts new file mode 100644 index 00000000000..fb9bfd543eb --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization9.ts @@ -0,0 +1,15 @@ +/// + +// @strict: true + +//// class T { +//// a: 1 | 2; +//// } + +verify.codeFix({ + description: `Add initializer to property 'a'`, + newFileContent: `class T { + a: 1 | 2 = 1; +}`, + index: 2 +}) \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization_all_1.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization_all_1.ts new file mode 100644 index 00000000000..46d50c3c32a --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization_all_1.ts @@ -0,0 +1,76 @@ +/// + +// @strict: true + +//// abstract class A { abstract a (); } +//// +//// class TT { constructor () {} } +//// +//// class AT extends A { a () {} } +//// +//// class Foo {} +//// +//// class T { +//// +//// a: string; +//// +//// static b: string; +//// +//// private c: string; +//// +//// d: number | undefined; +//// +//// e: string | number; +//// +//// f: 1; +//// +//// g: "123" | "456"; +//// +//// h: boolean; +//// +//// i: TT; +//// +//// j: A; +//// +//// k: AT; +//// +//// l: Foo; +//// } + +verify.codeFixAll({ + fixId: 'addMissingPropertyDefiniteAssignmentAssertions', + newFileContent: `abstract class A { abstract a (); } + +class TT { constructor () {} } + +class AT extends A { a () {} } + +class Foo {} + +class T { + + a!: string; + + static b: string; + + private c!: string; + + d: number | undefined; + + e!: string | number; + + f!: 1; + + g!: "123" | "456"; + + h!: boolean; + + i!: TT; + + j!: A; + + k!: AT; + + l!: Foo; +}` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization_all_2.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization_all_2.ts new file mode 100644 index 00000000000..ccf78aa1124 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization_all_2.ts @@ -0,0 +1,76 @@ +/// + +// @strict: true + +//// abstract class A { abstract a (); } +//// +//// class TT { constructor () {} } +//// +//// class AT extends A { a () {} } +//// +//// class Foo {} +//// +//// class T { +//// +//// a: string; +//// +//// static b: string; +//// +//// private c: string; +//// +//// d: number | undefined; +//// +//// e: string | number; +//// +//// f: 1; +//// +//// g: "123" | "456"; +//// +//// h: boolean; +//// +//// i: TT; +//// +//// j: A; +//// +//// k: AT; +//// +//// l: Foo; +//// } + +verify.codeFixAll({ + fixId: 'addMissingPropertyUndefinedType', + newFileContent: `abstract class A { abstract a (); } + +class TT { constructor () {} } + +class AT extends A { a () {} } + +class Foo {} + +class T { + + a: string | undefined; + + static b: string; + + private c: string | undefined; + + d: number | undefined; + + e: string | number | undefined; + + f: 1 | undefined; + + g: "123" | "456" | undefined; + + h: boolean | undefined; + + i: TT | undefined; + + j: A | undefined; + + k: AT | undefined; + + l: Foo | undefined; +}` +}); \ No newline at end of file diff --git a/tests/cases/fourslash/codeFixClassPropertyInitialization_all_3.ts b/tests/cases/fourslash/codeFixClassPropertyInitialization_all_3.ts new file mode 100644 index 00000000000..28518d3d16f --- /dev/null +++ b/tests/cases/fourslash/codeFixClassPropertyInitialization_all_3.ts @@ -0,0 +1,76 @@ +/// + +// @strict: true + +//// abstract class A { abstract a (); } +//// +//// class TT { constructor () {} } +//// +//// class AT extends A { a () {} } +//// +//// class Foo {} +//// +//// class T { +//// +//// a: string; +//// +//// static b: string; +//// +//// private c: string; +//// +//// d: number | undefined; +//// +//// e: string | number; +//// +//// f: 1; +//// +//// g: "123" | "456"; +//// +//// h: boolean; +//// +//// i: TT; +//// +//// j: A; +//// +//// k: AT; +//// +//// l: Foo; +//// } + +verify.codeFixAll({ + fixId: 'addMissingPropertyInitializer', + newFileContent: `abstract class A { abstract a (); } + +class TT { constructor () {} } + +class AT extends A { a () {} } + +class Foo {} + +class T { + + a: string = ""; + + static b: string; + + private c: string = ""; + + d: number | undefined; + + e: string | number = ""; + + f: 1 = 1; + + g: "123" | "456" = "123"; + + h: boolean = false; + + i: TT = new TT; + + j: A; + + k: AT = new AT; + + l: Foo = new Foo; +}` +}); \ No newline at end of file