Skip to content

Commit 591be7b

Browse files
authored
feat(44263): add quick fix for misspelled override error (microsoft#44266)
1 parent 703c1bc commit 591be7b

10 files changed

Lines changed: 131 additions & 2 deletions

File tree

src/compiler/checker.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ namespace ts {
635635
getSuggestionForNonexistentSymbol: (location, name, meaning) => getSuggestionForNonexistentSymbol(location, escapeLeadingUnderscores(name), meaning),
636636
getSuggestedSymbolForNonexistentModule,
637637
getSuggestionForNonexistentExport,
638+
getSuggestedSymbolForNonexistentClassMember,
638639
getBaseConstraintOfType,
639640
getDefaultFromTypeParameter: type => type && type.flags & TypeFlags.TypeParameter ? getDefaultFromTypeParameter(type as TypeParameter) : undefined,
640641
resolveName(name, location, meaning, excludeGlobals) {
@@ -27720,6 +27721,10 @@ namespace ts {
2772027721
}
2772127722
}
2772227723

27724+
function getSuggestedSymbolForNonexistentClassMember(name: string, baseType: Type): Symbol | undefined {
27725+
return getSpellingSuggestionForName(name, arrayFrom(getMembersOfSymbol(baseType.symbol).values()), SymbolFlags.ClassMember);
27726+
}
27727+
2772327728
function getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): Symbol | undefined {
2772427729
let props = getPropertiesOfType(containingType);
2772527730
if (typeof name !== "string") {
@@ -27739,7 +27744,7 @@ namespace ts {
2773927744
: strName === "class" ? find(properties, x => symbolName(x) === "className")
2774027745
: undefined;
2774127746
return jsxSpecific ?? getSpellingSuggestionForName(strName, properties, SymbolFlags.Value);
27742-
}
27747+
}
2774327748

2774427749
function getSuggestionForNonexistentProperty(name: Identifier | PrivateIdentifier | string, containingType: Type): string | undefined {
2774527750
const suggestion = getSuggestedSymbolForNonexistentProperty(name, containingType);
@@ -37346,7 +37351,7 @@ namespace ts {
3734637351

3734737352
const baseClassName = typeToString(baseWithThis);
3734837353
if (prop && !baseProp && hasOverride) {
37349-
const suggestion = getSpellingSuggestionForName(symbolName(declaredProp), arrayFrom(getMembersOfSymbol(baseType.symbol).values()), SymbolFlags.ClassMember);
37354+
const suggestion = getSuggestedSymbolForNonexistentClassMember(symbolName(declaredProp), baseType);
3735037355
suggestion ?
3735137356
error(member, Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1, baseClassName, symbolToString(suggestion)) :
3735237357
error(member, Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0, baseClassName);

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4218,6 +4218,7 @@ namespace ts {
42184218
/* @internal */ getSuggestedSymbolForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): Symbol | undefined;
42194219
/* @internal */ getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
42204220
/* @internal */ getSuggestedSymbolForNonexistentModule(node: Identifier, target: Symbol): Symbol | undefined;
4221+
/* @internal */ getSuggestedSymbolForNonexistentClassMember(name: string, baseType: Type): Symbol | undefined;
42214222
/* @internal */ getSuggestionForNonexistentExport(node: Identifier, target: Symbol): string | undefined;
42224223
getBaseConstraintOfType(type: Type): Type | undefined;
42234224
getDefaultFromTypeParameter(type: Type): Type | undefined;

src/services/codefixes/fixSpelling.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ namespace ts.codefix {
77
Diagnostics.Cannot_find_name_0_Did_you_mean_the_instance_member_this_0.code,
88
Diagnostics.Cannot_find_name_0_Did_you_mean_the_static_member_1_0.code,
99
Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2.code,
10+
Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0_Did_you_mean_1.code,
1011
// for JSX class components
1112
Diagnostics.No_overload_matches_this_call.code,
1213
// for JSX FC
@@ -73,6 +74,14 @@ namespace ts.codefix {
7374
const props = checker.getContextualTypeForArgumentAtIndex(tag, 0);
7475
suggestedSymbol = checker.getSuggestedSymbolForNonexistentJSXAttribute(node, props!);
7576
}
77+
else if (hasSyntacticModifier(parent, ModifierFlags.Override) && isClassElement(parent) && parent.name === node) {
78+
const baseDeclaration = findAncestor(node, isClassLike);
79+
const baseTypeNode = baseDeclaration ? getEffectiveBaseTypeNode(baseDeclaration) : undefined;
80+
const baseType = baseTypeNode ? checker.getTypeAtLocation(baseTypeNode) : undefined;
81+
if (baseType) {
82+
suggestedSymbol = checker.getSuggestedSymbolForNonexistentClassMember(getTextOfNode(node), baseType);
83+
}
84+
}
7685
else {
7786
const meaning = getMeaningFromLocation(node);
7887
const name = getTextOfNode(node);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
tests/cases/conformance/override/a.js(7,5): error TS4117: This member cannot have an 'override' modifier because it is not declared in the base class 'A'. Did you mean 'doSomething'?
2+
3+
4+
==== tests/cases/conformance/override/a.js (1 errors) ====
5+
class A {
6+
doSomething() {}
7+
}
8+
9+
class B extends A {
10+
/** @override */
11+
doSomethang() {}
12+
~~~~~~~~~~~
13+
!!! error TS4117: This member cannot have an 'override' modifier because it is not declared in the base class 'A'. Did you mean 'doSomething'?
14+
}
15+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/conformance/override/a.js ===
2+
class A {
3+
>A : Symbol(A, Decl(a.js, 0, 0))
4+
5+
doSomething() {}
6+
>doSomething : Symbol(A.doSomething, Decl(a.js, 0, 9))
7+
}
8+
9+
class B extends A {
10+
>B : Symbol(B, Decl(a.js, 2, 1))
11+
>A : Symbol(A, Decl(a.js, 0, 0))
12+
13+
/** @override */
14+
doSomethang() {}
15+
>doSomethang : Symbol(B.doSomethang, Decl(a.js, 4, 19))
16+
}
17+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
=== tests/cases/conformance/override/a.js ===
2+
class A {
3+
>A : A
4+
5+
doSomething() {}
6+
>doSomething : () => void
7+
}
8+
9+
class B extends A {
10+
>B : B
11+
>A : A
12+
13+
/** @override */
14+
doSomethang() {}
15+
>doSomethang : () => void
16+
}
17+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// @noImplicitOverride: true
2+
// @allowJs: true
3+
// @checkJs: true
4+
// @noEmit: true
5+
6+
// @Filename: a.js
7+
class A {
8+
doSomething() {}
9+
}
10+
11+
class B extends A {
12+
/** @override */
13+
doSomethang() {}
14+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @noImplicitOverride: true
4+
////class A {
5+
//// doSomething() {}
6+
////}
7+
////
8+
////class B extends A {
9+
//// override [|doSomethang|]() {}
10+
////}
11+
12+
verify.codeFix({
13+
index: 0,
14+
description: [ts.Diagnostics.Change_spelling_to_0.message, "doSomething"],
15+
newRangeContent: "doSomething"
16+
});
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @noImplicitOverride: true
4+
////abstract class A {
5+
//// abstract doSomething(): void;
6+
////}
7+
////abstract class B extends A {
8+
//// abstract override [|doSomethang|](): number;
9+
////}
10+
11+
verify.codeFix({
12+
index: 0,
13+
description: [ts.Diagnostics.Change_spelling_to_0.message, "doSomething"],
14+
newRangeContent: "doSomething"
15+
});
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @noImplicitOverride: true
4+
// @allowJs: true
5+
// @checkJs: true
6+
7+
// @Filename: a.js
8+
////class A {
9+
//// doSomething() {}
10+
////}
11+
////class B extends A {
12+
//// /** @override */
13+
//// [|doSomethang|]() {}
14+
////}
15+
16+
verify.codeFix({
17+
index: 0,
18+
description: [ts.Diagnostics.Change_spelling_to_0.message, "doSomething"],
19+
newRangeContent: "doSomething"
20+
});

0 commit comments

Comments
 (0)