mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-26 20:14:05 -05:00
feat(57240): Unimplemented abstract methods result in verbose, repetitive message (#57291)
This commit is contained in:
@@ -45069,9 +45069,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
|
||||
// NOTE: assignability is checked in checkClassDeclaration
|
||||
const baseProperties = getPropertiesOfType(baseType);
|
||||
let inheritedAbstractMemberNotImplementedError: Diagnostic | undefined;
|
||||
basePropertyCheck:
|
||||
for (const baseProperty of baseProperties) {
|
||||
|
||||
interface MemberInfo {
|
||||
missedProperties: string[];
|
||||
baseTypeName: string;
|
||||
typeName: string;
|
||||
}
|
||||
const notImplementedInfo = new Map<ClassLikeDeclaration, MemberInfo>();
|
||||
|
||||
basePropertyCheck: for (const baseProperty of baseProperties) {
|
||||
const base = getTargetSymbol(baseProperty);
|
||||
|
||||
if (base.flags & SymbolFlags.Prototype) {
|
||||
@@ -45108,38 +45114,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
continue basePropertyCheck;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inheritedAbstractMemberNotImplementedError) {
|
||||
inheritedAbstractMemberNotImplementedError = error(
|
||||
derivedClassDecl,
|
||||
Diagnostics.Non_abstract_class_0_does_not_implement_all_abstract_members_of_1,
|
||||
typeToString(type),
|
||||
typeToString(baseType),
|
||||
);
|
||||
}
|
||||
if (derivedClassDecl.kind === SyntaxKind.ClassExpression) {
|
||||
addRelatedInfo(
|
||||
inheritedAbstractMemberNotImplementedError,
|
||||
createDiagnosticForNode(
|
||||
baseProperty.valueDeclaration ?? (baseProperty.declarations && first(baseProperty.declarations)) ?? derivedClassDecl,
|
||||
Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1,
|
||||
symbolToString(baseProperty),
|
||||
typeToString(baseType),
|
||||
),
|
||||
);
|
||||
}
|
||||
else {
|
||||
addRelatedInfo(
|
||||
inheritedAbstractMemberNotImplementedError,
|
||||
createDiagnosticForNode(
|
||||
baseProperty.valueDeclaration ?? (baseProperty.declarations && first(baseProperty.declarations)) ?? derivedClassDecl,
|
||||
Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2,
|
||||
typeToString(type),
|
||||
symbolToString(baseProperty),
|
||||
typeToString(baseType),
|
||||
),
|
||||
);
|
||||
}
|
||||
const baseTypeName = typeToString(baseType);
|
||||
const typeName = typeToString(type);
|
||||
const basePropertyName = symbolToString(baseProperty);
|
||||
const missedProperties = append(notImplementedInfo.get(derivedClassDecl)?.missedProperties, basePropertyName);
|
||||
notImplementedInfo.set(derivedClassDecl, { baseTypeName, typeName, missedProperties });
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -45223,6 +45202,36 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
|
||||
error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, typeToString(baseType), symbolToString(base), typeToString(type));
|
||||
}
|
||||
}
|
||||
|
||||
for (const [errorNode, memberInfo] of notImplementedInfo) {
|
||||
if (length(memberInfo.missedProperties) === 1) {
|
||||
if (isClassExpression(errorNode)) {
|
||||
error(errorNode, Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1, first(memberInfo.missedProperties), memberInfo.baseTypeName);
|
||||
}
|
||||
else {
|
||||
error(errorNode, Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2, memberInfo.typeName, first(memberInfo.missedProperties), memberInfo.baseTypeName);
|
||||
}
|
||||
}
|
||||
else if (length(memberInfo.missedProperties) > 5) {
|
||||
const missedProperties = map(memberInfo.missedProperties.slice(0, 4), prop => `'${prop}'`).join(", ");
|
||||
const remainingMissedProperties = length(memberInfo.missedProperties) - 4;
|
||||
if (isClassExpression(errorNode)) {
|
||||
error(errorNode, Diagnostics.Non_abstract_class_expression_is_missing_implementations_for_the_following_members_of_0_Colon_1_and_2_more, memberInfo.baseTypeName, missedProperties, remainingMissedProperties);
|
||||
}
|
||||
else {
|
||||
error(errorNode, Diagnostics.Non_abstract_class_0_is_missing_implementations_for_the_following_members_of_1_Colon_2_and_3_more, memberInfo.typeName, memberInfo.baseTypeName, missedProperties, remainingMissedProperties);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const missedProperties = map(memberInfo.missedProperties, prop => `'${prop}'`).join(", ");
|
||||
if (isClassExpression(errorNode)) {
|
||||
error(errorNode, Diagnostics.Non_abstract_class_expression_is_missing_implementations_for_the_following_members_of_0_Colon_1, memberInfo.baseTypeName, missedProperties);
|
||||
}
|
||||
else {
|
||||
error(errorNode, Diagnostics.Non_abstract_class_0_is_missing_implementations_for_the_following_members_of_1_Colon_2, memberInfo.typeName, memberInfo.baseTypeName, missedProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isPropertyAbstractOrInterface(declaration: Declaration, baseDeclarationFlags: ModifierFlags) {
|
||||
|
||||
@@ -2484,7 +2484,7 @@
|
||||
"category": "Error",
|
||||
"code": 2514
|
||||
},
|
||||
"Non-abstract class '{0}' does not implement inherited abstract member '{1}' from class '{2}'.": {
|
||||
"Non-abstract class '{0}' does not implement inherited abstract member {1} from class '{2}'.": {
|
||||
"category": "Error",
|
||||
"code": 2515
|
||||
},
|
||||
@@ -2926,6 +2926,10 @@
|
||||
"category": "Error",
|
||||
"code": 2649
|
||||
},
|
||||
"Non-abstract class expression is missing implementations for the following members of '{0}': {1} and {2} more.": {
|
||||
"category": "Error",
|
||||
"code": 2650
|
||||
},
|
||||
"A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums.": {
|
||||
"category": "Error",
|
||||
"code": 2651
|
||||
@@ -2938,6 +2942,18 @@
|
||||
"category": "Error",
|
||||
"code": 2653
|
||||
},
|
||||
"Non-abstract class '{0}' is missing implementations for the following members of '{1}': {2}.": {
|
||||
"category": "Error",
|
||||
"code": 2654
|
||||
},
|
||||
"Non-abstract class '{0}' is missing implementations for the following members of '{1}': {2} and {3} more.": {
|
||||
"category": "Error",
|
||||
"code": 2655
|
||||
},
|
||||
"Non-abstract class expression is missing implementations for the following members of '{0}': {1}.": {
|
||||
"category": "Error",
|
||||
"code": 2656
|
||||
},
|
||||
"JSX expressions must have one parent element.": {
|
||||
"category": "Error",
|
||||
"code": 2657
|
||||
@@ -7937,10 +7953,6 @@
|
||||
"category": "Error",
|
||||
"code": 18051
|
||||
},
|
||||
"Non-abstract class '{0}' does not implement all abstract members of '{1}'": {
|
||||
"category": "Error",
|
||||
"code": 18052
|
||||
},
|
||||
"Its type '{0}' is not a valid JSX element type.": {
|
||||
"category": "Error",
|
||||
"code": 18053
|
||||
|
||||
@@ -26,8 +26,14 @@ import {
|
||||
} from "../_namespaces/ts.codefix";
|
||||
|
||||
const errorCodes = [
|
||||
Diagnostics.Non_abstract_class_0_does_not_implement_all_abstract_members_of_1.code,
|
||||
Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2.code,
|
||||
Diagnostics.Non_abstract_class_0_is_missing_implementations_for_the_following_members_of_1_Colon_2.code,
|
||||
Diagnostics.Non_abstract_class_0_is_missing_implementations_for_the_following_members_of_1_Colon_2_and_3_more.code,
|
||||
Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1.code,
|
||||
Diagnostics.Non_abstract_class_expression_is_missing_implementations_for_the_following_members_of_0_Colon_1.code,
|
||||
Diagnostics.Non_abstract_class_expression_is_missing_implementations_for_the_following_members_of_0_Colon_1_and_2_more.code,
|
||||
];
|
||||
|
||||
const fixId = "fixClassDoesntImplementInheritedAbstractMember";
|
||||
registerCodeFix({
|
||||
errorCodes,
|
||||
|
||||
Reference in New Issue
Block a user