Skip to content

Commit 5efd1cb

Browse files
author
Andy
authored
fixAddMissingMember: Support interface and don't crash on type parameter (#25995)
* fixAddMissingMember: Support interface and don't crash on type parameter * Remove InfoBase
1 parent 639fdcc commit 5efd1cb

6 files changed

+112
-75
lines changed

src/services/codefixes/fixAddMissingMember.ts

+66-67
Large diffs are not rendered by default.

src/services/codefixes/helpers.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ namespace ts.codefix {
117117
inJs: boolean,
118118
makeStatic: boolean,
119119
preferences: UserPreferences,
120+
body: boolean,
120121
): MethodDeclaration {
121122
const checker = context.program.getTypeChecker();
122123
const types = map(args,
@@ -142,7 +143,7 @@ namespace ts.codefix {
142143
createTypeParameterDeclaration(CharacterCodes.T + typeArguments!.length - 1 <= CharacterCodes.Z ? String.fromCharCode(CharacterCodes.T + i) : `T${i}`)),
143144
/*parameters*/ createDummyParameters(args.length, names, types, /*minArgumentCount*/ undefined, inJs),
144145
/*type*/ inJs ? undefined : createKeywordTypeNode(SyntaxKind.AnyKeyword),
145-
createStubbedMethodBody(preferences));
146+
body ? createStubbedMethodBody(preferences) : undefined);
146147
}
147148

148149
function createDummyParameters(argCount: number, names: (string | undefined)[] | undefined, types: (TypeNode | undefined)[] | undefined, minArgumentCount: number | undefined, inJs: boolean): ParameterDeclaration[] {

src/services/textChanges.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -409,14 +409,14 @@ namespace ts.textChanges {
409409
});
410410
}
411411

412-
public insertNodeAtClassStart(sourceFile: SourceFile, cls: ClassLikeDeclaration, newElement: ClassElement): void {
412+
public insertNodeAtClassStart(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration, newElement: ClassElement): void {
413413
const clsStart = cls.getStart(sourceFile);
414414
const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(getLineStartPositionForPosition(clsStart, sourceFile), clsStart, sourceFile, this.formatContext.options)
415415
+ this.formatContext.options.indentSize!;
416416
this.insertNodeAt(sourceFile, cls.members.pos, newElement, { indentation, ...this.getInsertNodeAtClassStartPrefixSuffix(sourceFile, cls) });
417417
}
418418

419-
private getInsertNodeAtClassStartPrefixSuffix(sourceFile: SourceFile, cls: ClassLikeDeclaration): { prefix: string, suffix: string } {
419+
private getInsertNodeAtClassStartPrefixSuffix(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration): { prefix: string, suffix: string } {
420420
if (cls.members.length === 0) {
421421
if (addToSeen(this.classesWithNodesInsertedAtStart, getNodeId(cls), cls)) {
422422
// For `class C {\n}`, don't add the trailing "\n"
@@ -708,7 +708,7 @@ namespace ts.textChanges {
708708
return skipTrivia(sourceFile.text, getAdjustedStartPosition(sourceFile, node, {}, Position.FullStart), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true);
709709
}
710710

711-
function getClassBraceEnds(cls: ClassLikeDeclaration, sourceFile: SourceFile): [number, number] {
711+
function getClassBraceEnds(cls: ClassLikeDeclaration | InterfaceDeclaration, sourceFile: SourceFile): [number, number] {
712712
return [findChildOfKind(cls, SyntaxKind.OpenBraceToken, sourceFile)!.end, findChildOfKind(cls, SyntaxKind.CloseBraceToken, sourceFile)!.end];
713713
}
714714

src/services/utilities.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1234,7 +1234,7 @@ namespace ts {
12341234
}
12351235

12361236
export function skipConstraint(type: Type): Type {
1237-
return type.isTypeParameter() ? type.getConstraint()! : type; // TODO: GH#18217
1237+
return type.isTypeParameter() ? type.getConstraint() || type : type;
12381238
}
12391239

12401240
export function getNameFromPropertyName(name: PropertyName): string | undefined {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
////interface I {}
2+
////
3+
////function f<T>(t: T): number {
4+
//// return t.foo;
5+
////}
6+
////
7+
////function g<T extends I>(t: T): number {
8+
//// return t.bar;
9+
////}
10+
11+
// No code fix for "foo"
12+
13+
verify.codeFixAvailable([
14+
{ description: "Declare property 'bar'" }, { description: "Add index signature for property 'bar'" },
15+
])
16+
17+
verify.codeFix({
18+
description: "Declare property 'bar'",
19+
index: 0,
20+
newFileContent:
21+
`interface I {
22+
bar: any;
23+
}
24+
25+
function f<T>(t: T): number {
26+
return t.foo;
27+
}
28+
29+
function g<T extends I>(t: T): number {
30+
return t.bar;
31+
}`,
32+
});

tests/cases/fourslash/codeFixUndeclaredPropertyAccesses.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
//// let t: T<number>;
1515
//// t.x;
1616

17-
verify.codeFixAvailable([{
18-
description: "Add missing enum member 'c'"
19-
}]);
17+
verify.codeFixAvailable([
18+
"Declare property 'y'",
19+
"Add index signature for property 'y'",
20+
"Declare method 'foo'",
21+
"Declare property 'foo'",
22+
"Add index signature for property 'foo'",
23+
"Add missing enum member 'c'",
24+
].map(description => ({ description })));

0 commit comments

Comments
 (0)