mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-30 10:29:18 -05:00
Merge pull request #14140 from aozgaa/ImplementMissingThis
Implement Missing Property of Type `this`
This commit is contained in:
@@ -21144,7 +21144,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)) {
|
||||
@@ -21154,7 +21162,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;
|
||||
const baseType = getBaseTypes(classType)[0];
|
||||
return baseType && getTypeWithThisArgument(baseType, classType.thisType);
|
||||
}
|
||||
|
||||
if (isTypeDeclaration(node)) {
|
||||
|
||||
@@ -3129,6 +3129,15 @@ namespace ts {
|
||||
return tryGetClassExtendingExpressionWithTypeArguments(node) !== undefined;
|
||||
}
|
||||
|
||||
export function isExpressionWithTypeArgumentsInClassImplementsClause(node: Node): node is ExpressionWithTypeArguments {
|
||||
return node.kind === SyntaxKind.ExpressionWithTypeArguments
|
||||
&& isEntityNameExpression((node as ExpressionWithTypeArguments).expression)
|
||||
&& 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,9 +25,9 @@ namespace ts.codefix {
|
||||
|
||||
const result: CodeAction[] = [];
|
||||
for (const implementedTypeNode of implementedTypeNodes) {
|
||||
const implementedType = checker.getTypeFromTypeNode(implementedTypeNode) as InterfaceType;
|
||||
// Note that this is ultimately derived from a map indexed by symbol names,
|
||||
// so duplicates cannot occur.
|
||||
const implementedType = checker.getTypeAtLocation(implementedTypeNode) as InterfaceType;
|
||||
const implementedTypeSymbols = checker.getPropertiesOfType(implementedType);
|
||||
const nonPrivateMembers = implementedTypeSymbols.filter(symbol => !(getModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private));
|
||||
|
||||
|
||||
@@ -23,8 +23,6 @@ namespace ts.codefix {
|
||||
* @returns Empty string iff there we can't figure out a representation for `symbol` in `enclosingDeclaration`.
|
||||
*/
|
||||
function getInsertionForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker, newlineChar: string): string {
|
||||
// const name = symbol.getName();
|
||||
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
|
||||
const declarations = symbol.getDeclarations();
|
||||
if (!(declarations && declarations.length)) {
|
||||
return "";
|
||||
@@ -34,6 +32,8 @@ namespace ts.codefix {
|
||||
const name = declaration.name ? declaration.name.getText() : undefined;
|
||||
const visibility = getVisibilityPrefixWithSpace(getModifierFlags(declaration));
|
||||
|
||||
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
|
||||
|
||||
switch (declaration.kind) {
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
|
||||
@@ -2,9 +2,17 @@
|
||||
|
||||
//// abstract class A {
|
||||
//// private _a: string;
|
||||
////
|
||||
//// abstract get a(): string;
|
||||
//// abstract set a(newName: string);
|
||||
////
|
||||
//// abstract get a(): number | string;
|
||||
//// abstract get b(): this;
|
||||
//// abstract get c(): A;
|
||||
////
|
||||
//// abstract set d(arg: number | string);
|
||||
//// abstract set e(arg: this);
|
||||
//// abstract set f(arg: A);
|
||||
////
|
||||
//// abstract get g(): string;
|
||||
//// abstract set g(newName: string);
|
||||
//// }
|
||||
////
|
||||
//// // Don't need to add anything in this case.
|
||||
@@ -13,5 +21,11 @@
|
||||
//// class C extends A {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
a: string;
|
||||
a: string | number;
|
||||
b: this;
|
||||
c: A;
|
||||
d: string | number;
|
||||
e: this;
|
||||
f: A;
|
||||
g: string;
|
||||
`);
|
||||
@@ -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) {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// abstract class A {
|
||||
//// abstract set c(arg: number | string);
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
c: string | number;
|
||||
`);
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// abstract class A {
|
||||
//// abstract f(): this;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
f(): this {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
`);
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
//// abstract class A {
|
||||
//// abstract x: number;
|
||||
//// abstract y: this;
|
||||
//// abstract z: A;
|
||||
//// abstract foo(): number;
|
||||
//// }
|
||||
////
|
||||
@@ -10,6 +12,8 @@
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: number;
|
||||
y: this;
|
||||
z: A;
|
||||
foo(): number {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// abstract class A {
|
||||
//// abstract get b(): number;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
b: number;
|
||||
`);
|
||||
/// <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.');
|
||||
}
|
||||
`);
|
||||
Reference in New Issue
Block a user