Skip to content

Commit 00021e1

Browse files
committed
Try get type from super type
1 parent 4d85f03 commit 00021e1

File tree

6 files changed

+137
-5
lines changed

6 files changed

+137
-5
lines changed

src/compiler/checker.ts

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15515,8 +15515,8 @@ namespace ts {
1551515515
return !node.typeParameters && !getEffectiveReturnTypeNode(node) && !!node.body && node.body.kind !== SyntaxKind.Block && isContextSensitive(node.body);
1551615516
}
1551715517

15518-
function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration {
15519-
return (isInJSFile(func) && isFunctionDeclaration(func) || isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func)) &&
15518+
function isContextSensitiveFunctionOrObjectLiteralMethodOrClassMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration {
15519+
return (isInJSFile(func) && isFunctionDeclaration(func) || isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func) || (noImplicitAny && isClassMethodInSubClass(func))) &&
1552015520
isContextSensitiveFunctionLikeDeclaration(func);
1552115521
}
1552215522

@@ -23516,7 +23516,7 @@ namespace ts {
2351623516
if (func.kind === SyntaxKind.ArrowFunction) {
2351723517
return undefined;
2351823518
}
23519-
if (isContextSensitiveFunctionOrObjectLiteralMethod(func)) {
23519+
if (isContextSensitiveFunctionOrObjectLiteralMethodOrClassMethod(func)) {
2352023520
const contextualSignature = getContextualSignature(func);
2352123521
if (contextualSignature) {
2352223522
const thisParameter = contextualSignature.thisParameter;
@@ -23576,7 +23576,7 @@ namespace ts {
2357623576
// Return contextual type of parameter or undefined if no contextual type is available
2357723577
function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type | undefined {
2357823578
const func = parameter.parent;
23579-
if (!isContextSensitiveFunctionOrObjectLiteralMethod(func)) {
23579+
if (!isContextSensitiveFunctionOrObjectLiteralMethodOrClassMethod(func)) {
2358023580
return undefined;
2358123581
}
2358223582
const iife = getImmediatelyInvokedFunctionExpression(func);
@@ -23954,6 +23954,28 @@ namespace ts {
2395423954
return getContextualTypeForObjectLiteralElement(node, contextFlags);
2395523955
}
2395623956

23957+
function getContextualTypeForClassMethod(node: MethodDeclaration): Type | undefined {
23958+
if (node.type || !isPropertyNameLiteral(node.name) || some(node.parameters, parameter => !!parameter.type)) {
23959+
return undefined;
23960+
}
23961+
23962+
const container = cast(node.parent, isClassLike);
23963+
const heritageElement = getClassExtendsHeritageElement(container);
23964+
Debug.assertIsDefined(heritageElement);
23965+
23966+
const baseType = getTypeOfNode(heritageElement);
23967+
if (baseType === errorType) {
23968+
return undefined;
23969+
}
23970+
23971+
const basePropType = getTypeOfPropertyOfType(baseType, getTextOfPropertyName(node.name))
23972+
if (!basePropType) {
23973+
return undefined
23974+
}
23975+
23976+
return basePropType
23977+
}
23978+
2395723979
function getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike, contextFlags?: ContextFlags) {
2395823980
const objectLiteral = <ObjectLiteralExpression>element.parent;
2395923981
const type = getApparentTypeOfContextualType(objectLiteral, contextFlags);
@@ -24089,6 +24111,7 @@ namespace ts {
2408924111
function getApparentTypeOfContextualType(node: Expression | MethodDeclaration, contextFlags?: ContextFlags): Type | undefined {
2409024112
const contextualType = isObjectLiteralMethod(node) ?
2409124113
getContextualTypeForObjectLiteralMethod(node, contextFlags) :
24114+
isClassMethodInSubClass(node) ? getContextualTypeForClassMethod(node) :
2409224115
getContextualType(node, contextFlags);
2409324116
const instantiatedType = instantiateContextualType(contextualType, node, contextFlags);
2409424117
if (instantiatedType && !(contextFlags && contextFlags & ContextFlags.NoConstraints && instantiatedType.flags & TypeFlags.TypeVariable)) {
@@ -24420,7 +24443,7 @@ namespace ts {
2442024443
// all identical ignoring their return type, the result is same signature but with return type as
2442124444
// union type of return types from these signatures
2442224445
function getContextualSignature(node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature | undefined {
24423-
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node));
24446+
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node) || isClassMethodInSubClass(node));
2442424447
const typeTagSignature = getSignatureOfTypeTag(node);
2442524448
if (typeTagSignature) {
2442624449
return typeTagSignature;

src/compiler/utilities.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1450,6 +1450,14 @@ namespace ts {
14501450
return node && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression;
14511451
}
14521452

1453+
export function isClassMethodInSubClass(node: Node): node is MethodDeclaration {
1454+
if (!node || !isMethodDeclaration(node) || !isClassLike(node.parent)) {
1455+
return false;
1456+
}
1457+
1458+
return !!getClassExtendsHeritageElement(node.parent);
1459+
}
1460+
14531461
export function isObjectLiteralOrClassExpressionMethod(node: Node): node is MethodDeclaration {
14541462
return node.kind === SyntaxKind.MethodDeclaration &&
14551463
(node.parent.kind === SyntaxKind.ObjectLiteralExpression ||
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//// [parameterTypeOfMethodLike.ts]
2+
class Base {
3+
method(x: number) { }
4+
}
5+
6+
class Derived extends Base {
7+
method(x) {
8+
x.toFixed(0)
9+
}
10+
}
11+
12+
//// [parameterTypeOfMethodLike.js]
13+
"use strict";
14+
var __extends = (this && this.__extends) || (function () {
15+
var extendStatics = function (d, b) {
16+
extendStatics = Object.setPrototypeOf ||
17+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
18+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
19+
return extendStatics(d, b);
20+
};
21+
return function (d, b) {
22+
extendStatics(d, b);
23+
function __() { this.constructor = d; }
24+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
25+
};
26+
})();
27+
var Base = /** @class */ (function () {
28+
function Base() {
29+
}
30+
Base.prototype.method = function (x) { };
31+
return Base;
32+
}());
33+
var Derived = /** @class */ (function (_super) {
34+
__extends(Derived, _super);
35+
function Derived() {
36+
return _super !== null && _super.apply(this, arguments) || this;
37+
}
38+
Derived.prototype.method = function (x) {
39+
x.toFixed(0);
40+
};
41+
return Derived;
42+
}(Base));
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
=== tests/cases/conformance/classes/methodDeclarations/parameterTypeOfMethodLike.ts ===
2+
class Base {
3+
>Base : Symbol(Base, Decl(parameterTypeOfMethodLike.ts, 0, 0))
4+
5+
method(x: number) { }
6+
>method : Symbol(Base.method, Decl(parameterTypeOfMethodLike.ts, 0, 12))
7+
>x : Symbol(x, Decl(parameterTypeOfMethodLike.ts, 1, 11))
8+
}
9+
10+
class Derived extends Base {
11+
>Derived : Symbol(Derived, Decl(parameterTypeOfMethodLike.ts, 2, 1))
12+
>Base : Symbol(Base, Decl(parameterTypeOfMethodLike.ts, 0, 0))
13+
14+
method(x) {
15+
>method : Symbol(Derived.method, Decl(parameterTypeOfMethodLike.ts, 4, 28))
16+
>x : Symbol(x, Decl(parameterTypeOfMethodLike.ts, 5, 11))
17+
18+
x.toFixed(0)
19+
>x.toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))
20+
>x : Symbol(x, Decl(parameterTypeOfMethodLike.ts, 5, 11))
21+
>toFixed : Symbol(Number.toFixed, Decl(lib.es5.d.ts, --, --))
22+
}
23+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
=== tests/cases/conformance/classes/methodDeclarations/parameterTypeOfMethodLike.ts ===
2+
class Base {
3+
>Base : Base
4+
5+
method(x: number) { }
6+
>method : (x: number) => void
7+
>x : number
8+
}
9+
10+
class Derived extends Base {
11+
>Derived : Derived
12+
>Base : Base
13+
14+
method(x) {
15+
>method : (x: number) => void
16+
>x : number
17+
18+
x.toFixed(0)
19+
>x.toFixed(0) : string
20+
>x.toFixed : (fractionDigits?: number | undefined) => string
21+
>x : number
22+
>toFixed : (fractionDigits?: number | undefined) => string
23+
>0 : 0
24+
}
25+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// @strict: true
2+
3+
class Base {
4+
method(x: number) { }
5+
}
6+
7+
class Derived extends Base {
8+
method(x): void {
9+
x.toFixed(0);
10+
}
11+
}

0 commit comments

Comments
 (0)