instantiate generic this param correctly

This commit is contained in:
Arthur Ozga 2017-02-22 16:15:16 -08:00
parent c77ea9e9ea
commit 5bcbd7aabc
9 changed files with 56 additions and 19 deletions

View file

@ -21106,7 +21106,15 @@ namespace ts {
}
if (isPartOfTypeNode(node)) {
return getTypeFromTypeNode(<TypeNode>node);
let typeFromTypeNode = getTypeFromTypeNode(<TypeNode>node);
if (typeFromTypeNode && isExpressionWithTypeArgumentsInClassImplementsClause(node)) {
const containingClass = getContainingClass(node);
const classType = getTypeOfNode(containingClass) as InterfaceType;
typeFromTypeNode = getTypeWithThisArgument(typeFromTypeNode, classType.thisType);
}
return typeFromTypeNode;
}
if (isPartOfExpression(node)) {
@ -21116,7 +21124,10 @@ namespace ts {
if (isExpressionWithTypeArgumentsInClassExtendsClause(node)) {
// A SyntaxKind.ExpressionWithTypeArguments is considered a type node, except when it occurs in the
// extends clause of a class. We handle that case here.
return getBaseTypes(<InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(node.parent.parent)))[0];
const classNode = getContainingClass(node);
const classType = getDeclaredTypeOfSymbol(getSymbolOfNode(classNode)) as InterfaceType; classType;
const baseType = getBaseTypes(classType)[0]; baseType;
return baseType && getTypeWithThisArgument(baseType, classType.thisType);
}
if (isTypeDeclaration(node)) {

View file

@ -3126,6 +3126,14 @@ namespace ts {
return tryGetClassExtendingExpressionWithTypeArguments(node) !== undefined;
}
export function isExpressionWithTypeArgumentsInClassImplementsClause(node: Node): boolean {
return node.kind === SyntaxKind.ExpressionWithTypeArguments
&& node.parent
&& (<HeritageClause>node.parent).token === SyntaxKind.ImplementsKeyword
&& node.parent.parent
&& isClassLike(node.parent.parent);
}
export function isEntityNameExpression(node: Expression): node is EntityNameExpression {
return node.kind === SyntaxKind.Identifier ||
node.kind === SyntaxKind.PropertyAccessExpression && isEntityNameExpression((<PropertyAccessExpression>node).expression);

View file

@ -22,8 +22,8 @@ namespace ts.codefix {
const classDecl = token.parent as ClassLikeDeclaration;
const startPos = classDecl.members.pos;
const classType = checker.getTypeAtLocation(classDecl) as InterfaceType;
const instantiatedExtendsType = checker.getBaseTypes(classType)[0];
const extendsNode = getClassExtendsHeritageClauseElement(classDecl);
const instantiatedExtendsType = checker.getTypeAtLocation(extendsNode);
// Note that this is ultimately derived from a map indexed by symbol names,
// so duplicates cannot occur.

View file

@ -17,7 +17,7 @@ namespace ts.codefix {
}
const startPos: number = classDecl.members.pos;
const classType = checker.getTypeAtLocation(classDecl);
const classType = checker.getTypeAtLocation(classDecl) as InterfaceType;
const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDecl);
const hasNumericIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.Number);
@ -25,7 +25,7 @@ namespace ts.codefix {
const result: CodeAction[] = [];
for (const implementedTypeNode of implementedTypeNodes) {
const implementedType = checker.getTypeFromTypeNode(implementedTypeNode) as InterfaceType;
const implementedType = checker.getTypeAtLocation(implementedTypeNode) as InterfaceType;
// Note that this is ultimately derived from a map indexed by symbol names,
// so duplicates cannot occur.
const implementedTypeSymbols = checker.getPropertiesOfType(implementedType);

View file

@ -32,22 +32,14 @@ namespace ts.codefix {
const name = declaration.name ? declaration.name.getText() : undefined;
const visibility = getVisibilityPrefixWithSpace(getModifierFlags(declaration));
const typeAtNewDeclaration = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
switch (declaration.kind) {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.PropertySignature:
case SyntaxKind.PropertyDeclaration:
let typeString: string | undefined = undefined;
const typeAtOldDeclaration = checker.getTypeAtLocation(declaration);
if ((typeAtOldDeclaration as TypeParameter).isThisType) {
typeString = "this";
}
else {
typeString = checker.typeToString(typeAtNewDeclaration, enclosingDeclaration, TypeFormatFlags.None);
}
const typeString = checker.typeToString(type, enclosingDeclaration, TypeFormatFlags.None);
return `${visibility}${name}: ${typeString};${newlineChar}`;
case SyntaxKind.MethodSignature:
@ -59,7 +51,7 @@ namespace ts.codefix {
// If there is more than one overload but no implementation signature
// (eg: an abstract method or interface declaration), there is a 1-1
// correspondence of declarations and signatures.
const signatures = checker.getSignaturesOfType(typeAtNewDeclaration, SignatureKind.Call);
const signatures = checker.getSignaturesOfType(type, SignatureKind.Call);
if (!(signatures && signatures.length > 0)) {
return "";
}

View file

@ -2,6 +2,7 @@
//// abstract class A {
//// abstract f(a: number, b: string): boolean;
//// abstract f(a: number, b: string): this;
//// abstract f(a: string, b: number): Function;
//// abstract f(a: string): Function;
//// }
@ -10,6 +11,7 @@
verify.rangeAfterCodeFix(`
f(a: number, b: string): boolean;
f(a: number, b: string): this;
f(a: string, b: number): Function;
f(a: string): Function;
f(a: any, b?: any) {

View file

@ -0,0 +1,13 @@
/// <reference path='fourslash.ts' />
//// abstract class A {
//// abstract f(): this;
//// }
////
//// class C extends A {[| |]}
verify.rangeAfterCodeFix(`
f(): this {
throw new Error('Method not implemented.');
}
`);

View file

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
//// abstract class A {
//// abstract x: this;
//// }
////
//// class C extends A {[| |]}
verify.rangeAfterCodeFix(`
x: this;
`);

View file

@ -1,14 +1,14 @@
/// <reference path='fourslash.ts' />
//// interface I {
//// f(x: number, y: string): I
//// f(x: number, y: this): I
//// }
////
//// class C implements I {[|
//// |]}
verify.rangeAfterCodeFix(`
f(x: number,y: string): I {
f(x: number,y: this): I {
throw new Error('Method not implemented.');
}
`);