instantiate generic this param correctly
This commit is contained in:
parent
c77ea9e9ea
commit
5bcbd7aabc
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 "";
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.');
|
||||
}
|
||||
`);
|
|
@ -0,0 +1,11 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// abstract class A {
|
||||
//// abstract x: this;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: this;
|
||||
`);
|
|
@ -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.');
|
||||
}
|
||||
`);
|
Loading…
Reference in a new issue