Skip to content

Commit 1c25034

Browse files
author
Arthur Ozga
committed
instantiate generic this param correctly
1 parent 1217ca7 commit 1c25034

9 files changed

+60
-16
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ namespace ts {
9797
getBaseTypes,
9898
getBaseTypeOfLiteralType,
9999
getWidenedType,
100+
getTypeWithThisArgument,
100101
getTypeFromTypeNode: node => {
101102
node = getParseTreeNode(node, isTypeNode);
102103
return node ? getTypeFromTypeNode(node) : unknownType;

src/compiler/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2411,6 +2411,7 @@
24112411
getIndexTypeOfType(type: Type, kind: IndexKind): Type;
24122412
getBaseTypes(type: InterfaceType): BaseType[];
24132413
getBaseTypeOfLiteralType(type: Type): Type;
2414+
getTypeWithThisArgument(type: Type, thisArgument?: Type): Type;
24142415
getWidenedType(type: Type): Type;
24152416
getReturnTypeOfSignature(signature: Signature): Type;
24162417
/**

src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ namespace ts.codefix {
2323
const startPos = classDecl.members.pos;
2424

2525
const classType = checker.getTypeAtLocation(classDecl) as InterfaceType;
26-
const instantiatedExtendsType = checker.getBaseTypes(classType)[0];
26+
const instantiatedExtendsType = checker.getTypeWithThisArgument(checker.getBaseTypes(classType)[0], classType.thisType);
2727

2828
// Note that this is ultimately derived from a map indexed by symbol names,
2929
// so duplicates cannot occur.

src/services/codefixes/fixClassIncorrectlyImplementsInterface.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ namespace ts.codefix {
1717
}
1818

1919
const startPos: number = classDecl.members.pos;
20-
const classType = checker.getTypeAtLocation(classDecl);
20+
const classType = checker.getTypeAtLocation(classDecl) as InterfaceType;
2121
const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDecl);
2222

2323
const hasNumericIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.Number);
2424
const hasStringIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.String);
2525

2626
const result: CodeAction[] = [];
2727
for (const implementedTypeNode of implementedTypeNodes) {
28-
const implementedType = checker.getTypeFromTypeNode(implementedTypeNode) as InterfaceType;
28+
const implementedType = checker.getTypeWithThisArgument(checker.getTypeFromTypeNode(implementedTypeNode), classType.thisType) as InterfaceType;
2929
// Note that this is ultimately derived from a map indexed by symbol names,
3030
// so duplicates cannot occur.
3131
const implementedTypeSymbols = checker.getPropertiesOfType(implementedType);

src/services/codefixes/helpers.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,22 +32,14 @@ namespace ts.codefix {
3232
const name = declaration.name ? declaration.name.getText() : undefined;
3333
const visibility = getVisibilityPrefixWithSpace(getModifierFlags(declaration));
3434

35-
const typeAtNewDeclaration = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
35+
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
3636

3737
switch (declaration.kind) {
3838
case SyntaxKind.GetAccessor:
3939
case SyntaxKind.SetAccessor:
4040
case SyntaxKind.PropertySignature:
4141
case SyntaxKind.PropertyDeclaration:
42-
let typeString: string | undefined = undefined;
43-
const typeAtOldDeclaration = checker.getTypeAtLocation(declaration);
44-
if ((typeAtOldDeclaration as TypeParameter).isThisType) {
45-
typeString = "this";
46-
}
47-
else {
48-
typeString = checker.typeToString(typeAtNewDeclaration, enclosingDeclaration, TypeFormatFlags.None);
49-
}
50-
42+
const typeString = checker.typeToString(type, enclosingDeclaration, TypeFormatFlags.None);
5143
return `${visibility}${name}: ${typeString};${newlineChar}`;
5244

5345
case SyntaxKind.MethodSignature:
@@ -59,7 +51,7 @@ namespace ts.codefix {
5951
// If there is more than one overload but no implementation signature
6052
// (eg: an abstract method or interface declaration), there is a 1-1
6153
// correspondence of declarations and signatures.
62-
const signatures = checker.getSignaturesOfType(typeAtNewDeclaration, SignatureKind.Call);
54+
const signatures = checker.getSignaturesOfType(type, SignatureKind.Call);
6355
if (!(signatures && signatures.length > 0)) {
6456
return "";
6557
}

tests/cases/fourslash/codeFixClassExtendAbstractMethod.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
//// abstract class A {
44
//// abstract f(a: number, b: string): boolean;
5+
//// abstract f(a: number, b: string): this;
56
//// abstract f(a: string, b: number): Function;
67
//// abstract f(a: string): Function;
78
//// }
@@ -10,6 +11,7 @@
1011

1112
verify.rangeAfterCodeFix(`
1213
f(a: number, b: string): boolean;
14+
f(a: number, b: string): this;
1315
f(a: string, b: number): Function;
1416
f(a: string): Function;
1517
f(a: any, b?: any) {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//// abstract class A {
4+
//// abstract f(): this;
5+
//// }
6+
////
7+
//// class C extends A {[| |]}
8+
9+
verify.rangeAfterCodeFix(`
10+
f(): this {
11+
throw new Error('Method not implemented.');
12+
}
13+
`);
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
/// <reference path='fourslash.ts' />
22

33
//// interface I {
4-
//// f(x: number, y: string): I
4+
//// f(x: number, y: this): I
55
//// }
66
////
77
//// class C implements I {[|
88
//// |]}
99

1010
verify.rangeAfterCodeFix(`
11-
f(x: number,y: string): I {
11+
f(x: number,y: this): I {
1212
throw new Error('Method not implemented.');
1313
}
1414
`);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
verify.quickInfos({
4+
1: "this: ContextualInterface",
5+
2: "(parameter) this: void"
6+
});
7+
8+
9+
10+
////interface ContextualInterface {
11+
//// m: number;
12+
//// method(this: this, n: number);
13+
////}
14+
////let o: ContextualInterface = {
15+
//// m: 12,
16+
//// method(n) {
17+
//// let x = this/*1*/.m;
18+
//// }
19+
////}
20+
////interface ContextualInterface2 {
21+
//// (this: void, n: number): void;
22+
////}
23+
////let contextualInterface2: ContextualInterface2 = function (th/*2*/is, n) { }
24+
25+
class A {
26+
x: number
27+
myMethod(): this { return this; }
28+
}
29+
30+
class B extends A {
31+
constructor(){
32+
super();
33+
this.myMethod();
34+
}
35+
}

0 commit comments

Comments
 (0)