From 5b739cf78ce901ae556c725221873801b45cd1a4 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Tue, 21 Mar 2017 22:54:06 -0700 Subject: [PATCH] respond to comments --- src/compiler/checker.ts | 118 +++++++++++++----- src/compiler/core.ts | 3 - src/compiler/transformers/es2017.ts | 2 +- src/compiler/transformers/esnext.ts | 4 +- src/compiler/transformers/ts.ts | 2 +- src/compiler/types.ts | 6 +- src/compiler/utilities.ts | 6 +- src/services/codefixes/fixAddMissingMember.ts | 2 +- .../fixClassIncorrectlyImplementsInterface.ts | 2 +- src/services/codefixes/helpers.ts | 40 +++--- ...assExtendAbstractMethodAnonymousClass.1.ts | 33 +++++ ...ClassImplementClassMemberAnonymousClass.ts | 20 +++ ...FixClassImplementClassPropertyTypeQuery.ts | 10 ++ 13 files changed, 180 insertions(+), 68 deletions(-) create mode 100644 tests/cases/fourslash/codeFixClassExtendAbstractMethodAnonymousClass.1.ts create mode 100644 tests/cases/fourslash/codeFixClassImplementClassMemberAnonymousClass.ts create mode 100644 tests/cases/fourslash/codeFixClassImplementClassPropertyTypeQuery.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index bb5046a8d6..dabc5407e1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -106,9 +106,9 @@ namespace ts { getParameterType: getTypeAtPosition, getReturnTypeOfSignature, getNonNullableType, - createTypeNode, - createIndexSignatureFromIndexInfo, - createSignatureParts, + typeToTypeNode, + indexInfoToIndexSignatureDeclaration, + signatureToSignatureDeclaration, getSymbolsInScope: (location, meaning) => { location = getParseTreeNode(location); return location ? getSymbolsInScope(location, meaning) : []; @@ -2196,8 +2196,8 @@ namespace ts { return undefined; } - const constraint = createTypeNode(getConstraintFromTypeParameter(type), enclosingDeclaration); - const defaultParameter = createTypeNode(getDefaultFromTypeParameter(type), enclosingDeclaration); + const constraint = typeToTypeNode(getConstraintFromTypeParameter(type), enclosingDeclaration); + const defaultParameter = typeToTypeNode(getDefaultFromTypeParameter(type), enclosingDeclaration); const name = symbolToString(type.symbol); return createTypeParameterDeclaration(name, constraint, defaultParameter); @@ -2206,7 +2206,7 @@ namespace ts { function createParameterDeclarationFromSymbol(parameterSymbol: Symbol, enclosingDeclaration: Node): ParameterDeclaration { const parameterDeclaration = parameterSymbol.declarations[0] as ParameterDeclaration; const parameterType = getTypeOfSymbol(parameterSymbol); - const parameterTypeNode = createTypeNode(parameterType, enclosingDeclaration); + const parameterTypeNode = typeToTypeNode(parameterType, enclosingDeclaration); // TODO: how should we clone members/modifiers? // TODO: check initializer accessibility correctly. const parameterNode = createParameter( @@ -2220,32 +2220,35 @@ namespace ts { return parameterNode; } - function createSignatureParts(signature: Signature, enclosingDeclaration: Node): SignatureParts { - return { - typeParameters: signature.typeParameters && signature.typeParameters.map(parameter => createTypeParameterDeclarationFromType(parameter,enclosingDeclaration)), - parameters: signature.parameters.map(parameter => createParameterDeclarationFromSymbol(parameter,enclosingDeclaration)), - type: createTypeNodeExceptAny(getReturnTypeOfSignature(signature)) - } + function signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration: Node): SignatureDeclaration { + const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => createTypeParameterDeclarationFromType(parameter, enclosingDeclaration)); + const parameters = signature.parameters.map(parameter => createParameterDeclarationFromSymbol(parameter, enclosingDeclaration)); + const type = createTypeNodeExceptAny(getReturnTypeOfSignature(signature)); + + return createSignatureDeclaration(kind, typeParameters, parameters, type); function createTypeNodeExceptAny(type: Type): TypeNode | undefined { - const typeNode = createTypeNode(type, enclosingDeclaration); + const typeNode = typeToTypeNode(type, enclosingDeclaration); return typeNode && typeNode.kind !== SyntaxKind.AnyKeyword ? typeNode : undefined; } } - function createTypeNode(type: Type, enclosingDeclaration: Node): TypeNode { - let undefinedArgumentIsError = true; + + // function typeToDisplayParts + + function typeToTypeNode(type: Type, enclosingDeclaration: Node, returnNodeOnError?: boolean): TypeNode { let encounteredError = false; let inObjectTypeLiteral = false; let checkAlias = true; let symbolStack: Symbol[] = undefined; const result = createTypeNodeWorker(type); - return encounteredError ? undefined: result; + // returnNodeOnError = true; // TODO: unset. + return encounteredError && !returnNodeOnError ? undefined: result; function createTypeNodeWorker(type: Type): TypeNode { if (!type) { - if (undefinedArgumentIsError) { encounteredError = true; } + encounteredError = true; return undefined; } @@ -2364,7 +2367,7 @@ namespace ts { const typeParameter = getTypeParameterFromMappedType(type); const typeParameterNode = createTypeParameterDeclarationFromType(typeParameter, enclosingDeclaration); - const templateTypeNode = createTypeNode(getTemplateTypeFromMappedType(type), enclosingDeclaration); + const templateTypeNode = typeToTypeNode(getTemplateTypeFromMappedType(type), enclosingDeclaration); const readonlyToken = (type).declaration && (type).declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined; const questionToken = (type).declaration && (type).declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined; @@ -2438,13 +2441,11 @@ namespace ts { if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) { const signature = resolved.callSignatures[0]; - const signatureParts = createSignatureParts(signature, enclosingDeclaration); - return createSignatureDeclaration(SyntaxKind.FunctionType, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type); + return signatureToSignatureDeclaration(signature, SyntaxKind.FunctionType, enclosingDeclaration); } if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) { const signature = resolved.constructSignatures[0]; - const signatureParts = createSignatureParts(signature, enclosingDeclaration); - return createSignatureDeclaration(SyntaxKind.ConstructorType, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type); + return signatureToSignatureDeclaration(signature, SyntaxKind.ConstructorType, enclosingDeclaration); } } @@ -2520,18 +2521,16 @@ namespace ts { function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] { const typeElements: TypeElement[] = []; for (const signature of resolvedType.callSignatures) { - const signatureParts = createSignatureParts(signature, enclosingDeclaration); - typeElements.push(createSignatureDeclaration(SyntaxKind.CallSignature, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type)); + typeElements.push(signatureToSignatureDeclaration(signature, SyntaxKind.CallSignature, enclosingDeclaration)); } for (const signature of resolvedType.constructSignatures) { - const signatureParts = createSignatureParts(signature, enclosingDeclaration); - typeElements.push(createSignatureDeclaration(SyntaxKind.ConstructSignature, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type)); + typeElements.push(signatureToSignatureDeclaration(signature, SyntaxKind.ConstructSignature, enclosingDeclaration)); } if (resolvedType.stringIndexInfo) { - typeElements.push(createIndexSignatureFromIndexInfo(resolvedType.stringIndexInfo, IndexKind.String, enclosingDeclaration)); + typeElements.push(indexInfoToIndexSignatureDeclaration(resolvedType.stringIndexInfo, IndexKind.String, enclosingDeclaration)); } if (resolvedType.numberIndexInfo) { - typeElements.push(createIndexSignatureFromIndexInfo(resolvedType.numberIndexInfo, IndexKind.Number, enclosingDeclaration)); + typeElements.push(indexInfoToIndexSignatureDeclaration(resolvedType.numberIndexInfo, IndexKind.Number, enclosingDeclaration)); } const properties = resolvedType.properties; @@ -2550,8 +2549,8 @@ namespace ts { if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) { const signatures = getSignaturesOfType(propertyType, SignatureKind.Call); for (const signature of signatures) { - const signatureParts = createSignatureParts(signature, enclosingDeclaration); - const methodDeclaration = createSignatureDeclaration(SyntaxKind.MethodSignature, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type, propertyName, optionalToken); + const methodDeclaration = signatureToSignatureDeclaration(signature, SyntaxKind.MethodSignature, enclosingDeclaration); + methodDeclaration.name = propertyName; methodDeclaration.questionToken = optionalToken; typeElements.push(methodDeclaration); } @@ -2571,7 +2570,6 @@ namespace ts { function createNameFromSymbol(symbol: Symbol): EntityName; function createNameFromSymbol(symbol: Symbol): EntityName { let parentSymbol: Symbol; - symbol; enclosingDeclaration; let meaning: SymbolFlags; // Get qualified name if the symbol is not a type parameter @@ -2580,18 +2578,49 @@ namespace ts { const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter; if (!isTypeParameter && enclosingDeclaration) { chain = getSymbolChain(symbol, meaning, /*endOfChain*/ true); + // TODO: check whether type pointed to by symbol requires type arguments to be printed. Debug.assert(chain && chain.length > 0); } else { chain = [symbol]; } + parentSymbol = undefined; const result = createEntityNameFromSymbolChain(chain, chain.length - 1); return result; function createEntityNameFromSymbolChain(chain: Symbol[], index: number): EntityName { Debug.assert(chain && 0 <= index && index < chain.length); - const identifier = createIdentifier(getNameOfSymbol(chain[index])); + // const parentIndex = index - 1; + const symbol = chain[index]; + let typeParameterString = ""; + if(index > 0) { + // TODO: is the parentSymbol wrong? + const parentSymbol = chain[index - 1]; + let typeParameters: TypeParameter[]; + if(getCheckFlags(symbol) & CheckFlags.Instantiated) { + typeParameters = getTypeParametersOfClassOrInterface(parentSymbol); + } + else { + const targetSymbol = getTargetSymbol(parentSymbol); + if(targetSymbol.flags & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeAlias)) { + typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol); + } + } + if(typeParameters && typeParameters.length > 0) { + encounteredError = true; + const writer = getSingleLineStringWriter(); + const displayBuilder = getSymbolDisplayBuilder(); + displayBuilder.buildDisplayForTypeParametersAndDelimiters(typeParameters, writer, enclosingDeclaration, 0); + typeParameterString = writer.string(); + releaseStringWriter(writer); + + } + } + const symbolName = getNameOfSymbol(symbol); + const symbolNameWithTypeParameters = typeParameterString.length > 0 ? `${symbolName}<${typeParameterString}>` : symbolName; + let identifier = createIdentifier(symbolNameWithTypeParameters); + return index > 0 ? createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier; } @@ -2628,10 +2657,31 @@ namespace ts { } } } + + function getNameOfSymbol(symbol: Symbol): string { + if (symbol.declarations && symbol.declarations.length) { + const declaration = symbol.declarations[0]; + if (declaration.name) { + return declarationNameToString(declaration.name); + } + if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) { + return declarationNameToString((declaration.parent).name); + } + encounteredError = true; + switch (declaration.kind) { + case SyntaxKind.ClassExpression: + return "(Anonymous class)"; + case SyntaxKind.FunctionExpression: + case SyntaxKind.ArrowFunction: + return "(Anonymous function)"; + } + } + return symbol.name; + } } } - function createIndexSignatureFromIndexInfo(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node): IndexSignatureDeclaration { + function indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node): IndexSignatureDeclaration { const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword); const name = getNameFromIndexInfo(indexInfo); @@ -2643,7 +2693,7 @@ namespace ts { /*questionToken*/ undefined, indexerTypeNode, /*initializer*/ undefined); - const typeNode = createTypeNode(indexInfo.type, enclosingDeclaration); + const typeNode = typeToTypeNode(indexInfo.type, enclosingDeclaration); return createIndexSignatureDeclaration( [indexingParameter], typeNode, diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 3f466e726d..c380a39611 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -1067,9 +1067,6 @@ namespace ts { /** Does nothing. */ export function noop(): void {} - /** Returns its first argument. */ - export function identity(x: X): X { return x; } - /** Throws an error because a function is not implemented. */ export function notImplemented(): never { throw new Error("Not implemented"); diff --git a/src/compiler/transformers/es2017.ts b/src/compiler/transformers/es2017.ts index 9c7bcf5b2a..088c57866d 100644 --- a/src/compiler/transformers/es2017.ts +++ b/src/compiler/transformers/es2017.ts @@ -125,7 +125,7 @@ namespace ts { visitNodes(node.modifiers, visitor, isModifier), node.asteriskToken, node.name, - node.questionToken, + /*questionToken*/ undefined, /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 2475e51119..83e84e6eab 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -475,7 +475,7 @@ namespace ts { /*modifiers*/ undefined, node.dotDotDotToken, getGeneratedNameForNode(node), - node.questionToken, + /*questionToken*/ undefined, /*type*/ undefined, visitNode(node.initializer, visitor, isExpression) ); @@ -541,7 +541,7 @@ namespace ts { ? undefined : node.asteriskToken, visitNode(node.name, visitor, isPropertyName), - visitNode(node.questionToken, visitor, isToken), + visitNode(/*questionToken*/ undefined, visitor, isToken), /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts index bbc588ee9f..6dc643b954 100644 --- a/src/compiler/transformers/ts.ts +++ b/src/compiler/transformers/ts.ts @@ -2049,7 +2049,7 @@ namespace ts { visitNodes(node.modifiers, modifierVisitor, isModifier), node.asteriskToken, visitPropertyNameOfClassElement(node), - node.questionToken, + /*questionToken*/ undefined, /*typeParameters*/ undefined, visitParameterList(node.parameters, visitor, context), /*type*/ undefined, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 2579ee2eaf..5ccdd79f19 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2473,11 +2473,11 @@ namespace ts { getNonNullableType(type: Type): Type; /** Note that the resulting nodes cannot be checked. */ - createTypeNode(type: Type, enclosingDeclaration: Node): TypeNode; + typeToTypeNode(type: Type, enclosingDeclaration: Node): TypeNode; /** Note that the resulting nodes cannot be checked. */ - createIndexSignatureFromIndexInfo(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node): IndexSignatureDeclaration; + indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration: Node): IndexSignatureDeclaration; /** Note that the resulting nodes cannot be checked. */ - createSignatureParts(signature: Signature, enclosingDeclaration: Node): SignatureParts; + signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration: Node): SignatureDeclaration; getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[]; getSymbolAtLocation(node: Node): Symbol; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 47642291c2..656b3c5db4 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -744,8 +744,8 @@ namespace ts { // // let a: A.B.C; // - // Calling isPartOfTypeNode would consider the qualified name A.B a type node. Only C or - // A.B.C is a type node. + // Calling isPartOfTypeNode would consider the qualified name A.B a type node. + // Only C and A.B.C are type nodes. if (SyntaxKind.FirstTypeNode <= parent.kind && parent.kind <= SyntaxKind.LastTypeNode) { return true; } @@ -3735,7 +3735,7 @@ namespace ts { * of a TypeNode. */ export function isTypeNode(node: Node): node is TypeNode { - return isTypeNodeKind(node.kind); + return node && isTypeNodeKind(node.kind) && (!node.parent || isPartOfTypeNode(node)); } // Binding patterns diff --git a/src/services/codefixes/fixAddMissingMember.ts b/src/services/codefixes/fixAddMissingMember.ts index a67c6791ba..bf706e7ded 100644 --- a/src/services/codefixes/fixAddMissingMember.ts +++ b/src/services/codefixes/fixAddMissingMember.ts @@ -38,7 +38,7 @@ namespace ts.codefix { const checker = context.program.getTypeChecker(); const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right))); - typeNode = checker.createTypeNode(widenedType, classDeclaration) || typeNode; + typeNode = checker.typeToTypeNode(widenedType, classDeclaration) || typeNode; } const openBrace = getOpenBraceOfClassLike(classDeclaration, sourceFile); diff --git a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts index 365fd35801..3b1b99febb 100644 --- a/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts +++ b/src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts @@ -53,7 +53,7 @@ namespace ts.codefix { if (!indexInfoOfKind) { return; } - const newIndexSignatureDeclaration = checker.createIndexSignatureFromIndexInfo(indexInfoOfKind, kind, classDeclaration); + const newIndexSignatureDeclaration = checker.indexInfoToIndexSignatureDeclaration(indexInfoOfKind, kind, classDeclaration); newNodes.push(newIndexSignatureDeclaration); } diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts index 4a9ee25228..3b4a75caa7 100644 --- a/src/services/codefixes/helpers.ts +++ b/src/services/codefixes/helpers.ts @@ -64,7 +64,7 @@ namespace ts.codefix { const declaration = declarations[0] as Declaration; const name = declaration.name ? getSynthesizedDeepClone(declaration.name) as PropertyName : undefined; const visibilityModifier = createVisibilityModifier(getModifierFlags(declaration)); - const modifiers = visibilityModifier ? [visibilityModifier] : undefined; + const modifiers = visibilityModifier ? createNodeArray([visibilityModifier]) : undefined; const type = checker.getWidenedType(checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration)); switch (declaration.kind) { @@ -72,7 +72,7 @@ namespace ts.codefix { case SyntaxKind.SetAccessor: case SyntaxKind.PropertySignature: case SyntaxKind.PropertyDeclaration: - const typeNode = checker.createTypeNode(type, enclosingDeclaration); + const typeNode = checker.typeToTypeNode(type, enclosingDeclaration); const property = createProperty( /*decorators*/undefined, modifiers, @@ -99,30 +99,32 @@ namespace ts.codefix { if (declarations.length === 1) { Debug.assert(signatures.length === 1); const signature = signatures[0]; - const signatureParts = checker.createSignatureParts(signature, enclosingDeclaration); - return createStubbedMethod(modifiers, name, optional, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type); + const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration) as MethodDeclaration; + signatureDeclaration.modifiers = modifiers; + signatureDeclaration.name = name; + signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined; + signatureDeclaration.body = createStubbedMethodBody(); + return signatureDeclaration; } let signatureDeclarations = []; for (let i = 0; i < signatures.length; i++) { const signature = signatures[i]; - const signatureParts = checker.createSignatureParts(signature, enclosingDeclaration); - signatureDeclarations.push(createMethod( - /*decorators*/ undefined, - modifiers, - /*asteriskToken*/ undefined, - name, - optional ? createToken(SyntaxKind.QuestionToken) : undefined, - signatureParts.typeParameters, - signatureParts.parameters, - signatureParts.type, - /*body*/undefined)); + const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration) as MethodDeclaration; + signatureDeclaration.modifiers = modifiers; + signatureDeclaration.name = name; + signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined; + signatureDeclarations.push(signatureDeclaration); } if (declarations.length > signatures.length) { let signature = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration); - const signatureParts = checker.createSignatureParts(signature, enclosingDeclaration); - signatureDeclarations.push(createStubbedMethod(modifiers, name, optional, signatureParts.typeParameters, signatureParts.parameters, signatureParts.type)); + const signatureDeclaration = checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration) as MethodDeclaration; + signatureDeclaration.modifiers = modifiers; + signatureDeclaration.name = name; + signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined; + signatureDeclaration.body = createStubbedMethodBody(); + signatureDeclarations.push(signatureDeclaration); } else { Debug.assert(declarations.length === signatures.length); @@ -195,9 +197,9 @@ namespace ts.codefix { export function createStubbedMethod(modifiers: Modifier[], name: PropertyName, optional: boolean, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], returnType: TypeNode | undefined) { return createMethod( - /*decorators*/undefined, + /*decorators*/ undefined, modifiers, - /*asteriskToken*/undefined, + /*asteriskToken*/ undefined, name, optional ? createToken(SyntaxKind.QuestionToken) : undefined, typeParameters, diff --git a/tests/cases/fourslash/codeFixClassExtendAbstractMethodAnonymousClass.1.ts b/tests/cases/fourslash/codeFixClassExtendAbstractMethodAnonymousClass.1.ts new file mode 100644 index 0000000000..134ce17376 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassExtendAbstractMethodAnonymousClass.1.ts @@ -0,0 +1,33 @@ +/// + +class A { + foo() { + return class { x: number; } + } + bar() { + return new class { x: number; } + } +} +class B { + foo() { + return class { + x: X; + } + } +} + + +class D extends A { } + +verify.rangeAfterCodeFix(` + f(a: number, b: string): boolean; + f(a: number, b: string): this; + f(a: string, b: number): Function; + f(a: string): Function; + f(a: any, b?: any) { + throw new Error("Method not implemented."); + } + foo(): number { + throw new Error("Method not implemented."); + } +`); diff --git a/tests/cases/fourslash/codeFixClassImplementClassMemberAnonymousClass.ts b/tests/cases/fourslash/codeFixClassImplementClassMemberAnonymousClass.ts new file mode 100644 index 0000000000..a8a024d194 --- /dev/null +++ b/tests/cases/fourslash/codeFixClassImplementClassMemberAnonymousClass.ts @@ -0,0 +1,20 @@ +/// + +//// class A { +//// foo() { +//// return class { x: number; } +//// } +//// bar() { +//// return new class { x: number; } +//// } +//// } +//// class C implements A {[| |]} + +verify.rangeAfterCodeFix(` + foo() { + throw new Error("Method not implemented."); + } + bar() { + throw new Error("Method not implemented."); + } +`); diff --git a/tests/cases/fourslash/codeFixClassImplementClassPropertyTypeQuery.ts b/tests/cases/fourslash/codeFixClassImplementClassPropertyTypeQuery.ts new file mode 100644 index 0000000000..4a5663a8ba --- /dev/null +++ b/tests/cases/fourslash/codeFixClassImplementClassPropertyTypeQuery.ts @@ -0,0 +1,10 @@ +/// + +//// class A { +//// A: typeof A; +//// } +//// class D implements A {[| |]} + +verify.rangeAfterCodeFix(` + A: typeof A; +`);