Skip to content

Commit 8094b2c

Browse files
committed
Improve contextual typing of partially annotated signatures
1 parent 65b1cf6 commit 8094b2c

File tree

1 file changed

+47
-19
lines changed

1 file changed

+47
-19
lines changed

src/compiler/checker.ts

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3144,8 +3144,7 @@ namespace ts {
31443144
// Use contextual parameter type if one is available
31453145
let type: Type;
31463146
if (declaration.symbol.name === "this") {
3147-
const thisParameter = getContextualThisParameter(func);
3148-
type = thisParameter ? getTypeOfSymbol(thisParameter) : undefined;
3147+
type = getContextualThisParameterType(func);
31493148
}
31503149
else {
31513150
type = getContextuallyTypedParameterType(<ParameterDeclaration>declaration);
@@ -4789,9 +4788,6 @@ namespace ts {
47894788
if (isJSConstructSignature) {
47904789
minArgumentCount--;
47914790
}
4792-
if (!thisParameter && isObjectLiteralMethod(declaration)) {
4793-
thisParameter = getContextualThisParameter(declaration);
4794-
}
47954791

47964792
const classType = declaration.kind === SyntaxKind.Constructor ?
47974793
getDeclaredTypeOfClassOrInterface(getMergedSymbol((<ClassDeclaration>declaration.parent).symbol))
@@ -6101,9 +6097,24 @@ namespace ts {
61016097
}
61026098

61036099
function isContextSensitiveFunctionLikeDeclaration(node: FunctionLikeDeclaration) {
6104-
const areAllParametersUntyped = !forEach(node.parameters, p => p.type);
6105-
const isNullaryArrow = node.kind === SyntaxKind.ArrowFunction && !node.parameters.length;
6106-
return !node.typeParameters && areAllParametersUntyped && !isNullaryArrow;
6100+
// Functions with type parameters are not context sensitive.
6101+
if (node.typeParameters) {
6102+
return false;
6103+
}
6104+
// Functions with any parameters that lack type annotations are context sensitive.
6105+
if (forEach(node.parameters, p => !p.type)) {
6106+
return true;
6107+
}
6108+
// For arrow functions we now know we're not context sensitive.
6109+
if (node.kind === SyntaxKind.ArrowFunction) {
6110+
return false;
6111+
}
6112+
// If the first parameter is not an explicit 'this' parameter, then the function has
6113+
// an implicit 'this' parameter which is subject to contextual typing. Otherwise we
6114+
// know that all parameters (including 'this') have type annotations and nothing is
6115+
// subject to contextual typing.
6116+
const parameter = firstOrUndefined(node.parameters);
6117+
return !(parameter && parameter.name.kind === SyntaxKind.Identifier && (<Identifier>parameter.name).text === "this");
61076118
}
61086119

61096120
function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration {
@@ -9629,7 +9640,7 @@ namespace ts {
96299640
}
96309641
}
96319642

9632-
const thisType = getThisTypeOfDeclaration(container);
9643+
let thisType = getThisTypeOfDeclaration(container) || getContextualThisParameterType(container);
96339644
if (thisType) {
96349645
return thisType;
96359646
}
@@ -9869,14 +9880,16 @@ namespace ts {
98699880
}
98709881
}
98719882

9872-
function getContextualThisParameter(func: FunctionLikeDeclaration): Symbol {
9883+
function getContextualThisParameterType(func: FunctionLikeDeclaration): Type {
98739884
if (isContextSensitiveFunctionOrObjectLiteralMethod(func) && func.kind !== SyntaxKind.ArrowFunction) {
98749885
const contextualSignature = getContextualSignature(func);
98759886
if (contextualSignature) {
9876-
return contextualSignature.thisParameter;
9887+
const thisParameter = contextualSignature.thisParameter;
9888+
if (thisParameter) {
9889+
return getTypeOfSymbol(thisParameter);
9890+
}
98779891
}
98789892
}
9879-
98809893
return undefined;
98819894
}
98829895

@@ -12840,21 +12853,36 @@ namespace ts {
1284012853

1284112854
function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper) {
1284212855
const len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0);
12856+
if (isInferentialContext(mapper)) {
12857+
for (let i = 0; i < len; i++) {
12858+
const declaration = <ParameterDeclaration>signature.parameters[i].valueDeclaration;
12859+
if (declaration.type) {
12860+
inferTypes(mapper.context, getTypeFromTypeNode(declaration.type), getTypeAtPosition(context, i));
12861+
}
12862+
}
12863+
}
1284312864
if (context.thisParameter) {
12844-
if (!signature.thisParameter) {
12845-
signature.thisParameter = createTransientSymbol(context.thisParameter, undefined);
12865+
const parameter = signature.thisParameter;
12866+
if (!parameter || parameter.valueDeclaration && !(<ParameterDeclaration>parameter.valueDeclaration).type) {
12867+
if (!parameter) {
12868+
signature.thisParameter = createTransientSymbol(context.thisParameter, undefined);
12869+
}
12870+
assignTypeToParameterAndFixTypeParameters(signature.thisParameter, getTypeOfSymbol(context.thisParameter), mapper);
1284612871
}
12847-
assignTypeToParameterAndFixTypeParameters(signature.thisParameter, getTypeOfSymbol(context.thisParameter), mapper);
1284812872
}
1284912873
for (let i = 0; i < len; i++) {
1285012874
const parameter = signature.parameters[i];
12851-
const contextualParameterType = getTypeAtPosition(context, i);
12852-
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
12875+
if (!(<ParameterDeclaration>parameter.valueDeclaration).type) {
12876+
const contextualParameterType = getTypeAtPosition(context, i);
12877+
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
12878+
}
1285312879
}
1285412880
if (signature.hasRestParameter && isRestParameterIndex(context, signature.parameters.length - 1)) {
1285512881
const parameter = lastOrUndefined(signature.parameters);
12856-
const contextualParameterType = getTypeOfSymbol(lastOrUndefined(context.parameters));
12857-
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
12882+
if (!(<ParameterDeclaration>parameter.valueDeclaration).type) {
12883+
const contextualParameterType = getTypeOfSymbol(lastOrUndefined(context.parameters));
12884+
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
12885+
}
1285812886
}
1285912887
}
1286012888

0 commit comments

Comments
 (0)