fix(54694): Class incorrectly implements interface generated with template string literal mapped type (#54715)

This commit is contained in:
Oleksandr T
2023-07-20 23:51:32 +03:00
committed by GitHub
parent 5128e06a9d
commit 2136bef652
5 changed files with 67 additions and 23 deletions

View File

@@ -6,27 +6,32 @@ import {
Block,
CallExpression,
CharacterCodes,
CheckFlags,
ClassLikeDeclaration,
CodeFixContextBase,
combine,
Debug,
Declaration,
Diagnostics,
emptyArray,
EntityName,
Expression,
factory,
find,
firstOrUndefined,
flatMap,
FunctionDeclaration,
FunctionExpression,
GetAccessorDeclaration,
getAllAccessorDeclarations,
getCheckFlags,
getEffectiveModifierFlags,
getEmitScriptTarget,
getFirstIdentifier,
getModuleSpecifierResolverHost,
getNameForExportedSymbol,
getNameOfDeclaration,
getPropertyNameFromType,
getQuotePreference,
getSetAccessorValueParameter,
getSynthesizedDeepClone,
@@ -52,6 +57,7 @@ import {
isSetAccessorDeclaration,
isStringLiteral,
isTypeNode,
isTypeUsableAsPropertyName,
isYieldExpression,
LanguageServiceHost,
length,
@@ -91,6 +97,7 @@ import {
textChanges,
TextSpan,
textSpanEnd,
TransientSymbol,
tryCast,
TsConfigSourceFile,
Type,
@@ -98,6 +105,7 @@ import {
TypeFlags,
TypeNode,
TypeParameterDeclaration,
unescapeLeadingUnderscores,
UnionType,
UserPreferences,
visitEachChild,
@@ -174,7 +182,7 @@ export function addNewNodeForMemberSymbol(
isAmbient = false,
): void {
const declarations = symbol.getDeclarations();
const declaration = declarations?.[0];
const declaration = firstOrUndefined(declarations);
const checker = context.program.getTypeChecker();
const scriptTarget = getEmitScriptTarget(context.program.getCompilerOptions());
@@ -193,7 +201,7 @@ export function addNewNodeForMemberSymbol(
* In such cases, we assume the declaration to be a `PropertySignature`.
*/
const kind = declaration?.kind ?? SyntaxKind.PropertySignature;
const declarationName = getSynthesizedDeepClone(getNameOfDeclaration(declaration), /*includeTrivia*/ false) as PropertyName;
const declarationName = createDeclarationName(symbol, declaration);
const effectiveModifierFlags = declaration ? getEffectiveModifierFlags(declaration) : ModifierFlags.None;
let modifierFlags = effectiveModifierFlags & ModifierFlags.Static;
modifierFlags |=
@@ -310,7 +318,6 @@ export function addNewNodeForMemberSymbol(
if (method) addClassElement(method);
}
function createModifiers(): NodeArray<Modifier> | undefined {
let modifiers: Modifier[] | undefined;
@@ -344,6 +351,16 @@ export function addNewNodeForMemberSymbol(
function createTypeNode(typeNode: TypeNode | undefined) {
return getSynthesizedDeepClone(typeNode, /*includeTrivia*/ false);
}
function createDeclarationName(symbol: Symbol, declaration: Declaration | undefined): PropertyName {
if (getCheckFlags(symbol) & CheckFlags.Mapped) {
const nameType = (symbol as TransientSymbol).links.nameType;
if (nameType && isTypeUsableAsPropertyName(nameType)) {
return factory.createIdentifier(unescapeLeadingUnderscores(getPropertyNameFromType(nameType)));
}
}
return getSynthesizedDeepClone(getNameOfDeclaration(declaration), /*includeTrivia*/ false) as PropertyName;
}
}
/** @internal */