diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8551652c176d5..346fddc303db1 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -153,6 +153,10 @@ namespace ts { node = getParseTreeNode(node, isExpression); return node ? getContextualType(node) : undefined; }, + getContextualSignature: node => { + node = getParseTreeNode(node, isContextualSignatureNode); + return node ? getContextualSignature(node) : undefined; + }, getFullyQualifiedName, getResolvedSignature: (node, candidatesOutArray?) => { node = getParseTreeNode(node, isCallLikeExpression); @@ -8244,14 +8248,13 @@ namespace ts { // Returns true if the given expression contains (at any level of nesting) a function or arrow expression // that is subject to contextual typing. - function isContextSensitive(node: Expression | MethodDeclaration | ObjectLiteralElementLike | JsxAttributeLike): boolean { - Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); + function isContextSensitive(node: Expression | ObjectLiteralElementLike & { parent: ObjectLiteralExpression } | JsxAttributeLike): boolean { switch (node.kind) { case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: return isContextSensitiveFunctionLikeDeclaration(<FunctionExpression>node); case SyntaxKind.ObjectLiteralExpression: - return forEach((<ObjectLiteralExpression>node).properties, isContextSensitive); + return forEach((<ObjectLiteralExpression>node).properties as Array<ObjectLiteralElementLike & { parent: ObjectLiteralExpression }>, isContextSensitive); case SyntaxKind.ArrayLiteralExpression: return forEach((<ArrayLiteralExpression>node).elements, isContextSensitive); case SyntaxKind.ConditionalExpression: @@ -8301,8 +8304,8 @@ namespace ts { return !(parameter && parameterIsThisKeyword(parameter)); } - function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration { - return (isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func)) && isContextSensitiveFunctionLikeDeclaration(func); + function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is ContextualSignatureNode { + return isContextualSignatureNode(func) && isContextSensitiveFunctionLikeDeclaration(func); } function getTypeWithoutSignatures(type: Type): Type { @@ -13011,18 +13014,12 @@ namespace ts { return sourceLength < targetParameterCount; } - function isFunctionExpressionOrArrowFunction(node: Node): node is FunctionExpression | ArrowFunction { - return node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.ArrowFunction; - } - function getContextualSignatureForFunctionLikeDeclaration(node: FunctionLikeDeclaration): Signature { // Only function expressions, arrow functions, and object literal methods are contextually typed. - return isFunctionExpressionOrArrowFunction(node) || isObjectLiteralMethod(node) - ? getContextualSignature(<FunctionExpression>node) - : undefined; + return isContextualSignatureNode(node) ? getContextualSignature(node) : undefined; } - function getContextualTypeForFunctionLikeDeclaration(node: FunctionExpression | ArrowFunction | MethodDeclaration) { + function getContextualTypeForFunctionLikeDeclaration(node: ContextualSignatureNode): Type | undefined { return isObjectLiteralMethod(node) ? getContextualTypeForObjectLiteralMethod(node) : getApparentTypeOfContextualType(node); @@ -13033,8 +13030,7 @@ namespace ts { // If the contextual type is a union type, get the signature from each type possible and if they are // all identical ignoring their return type, the result is same signature but with return type as // union type of return types from these signatures - function getContextualSignature(node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature { - Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); + function getContextualSignature(node: ContextualSignatureNode): Signature { const type = getContextualTypeForFunctionLikeDeclaration(node); if (!type) { return undefined; @@ -13257,14 +13253,14 @@ namespace ts { isObjectLiteralMethod(memberDecl)) { let type: Type; if (memberDecl.kind === SyntaxKind.PropertyAssignment) { - type = checkPropertyAssignment(<PropertyAssignment>memberDecl, checkMode); + type = checkPropertyAssignment(memberDecl, checkMode); } else if (memberDecl.kind === SyntaxKind.MethodDeclaration) { - type = checkObjectLiteralMethod(<MethodDeclaration>memberDecl, checkMode); + type = checkObjectLiteralMethod(memberDecl, checkMode); } else { Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment); - type = checkExpressionForMutableLocation((<ShorthandPropertyAssignment>memberDecl).name, checkMode); + type = checkExpressionForMutableLocation(memberDecl.name, checkMode); } typeFlags |= type.flags; @@ -13273,8 +13269,8 @@ namespace ts { // If object literal is an assignment pattern and if the assignment pattern specifies a default value // for the property, make the property optional. const isOptional = - (memberDecl.kind === SyntaxKind.PropertyAssignment && hasDefaultValue((<PropertyAssignment>memberDecl).initializer)) || - (memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment && (<ShorthandPropertyAssignment>memberDecl).objectAssignmentInitializer); + (memberDecl.kind === SyntaxKind.PropertyAssignment && hasDefaultValue(memberDecl.initializer)) || + (memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment && memberDecl.objectAssignmentInitializer); if (isOptional) { prop.flags |= SymbolFlags.Optional; } @@ -16525,9 +16521,7 @@ namespace ts { } } - function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | MethodDeclaration, checkMode?: CheckMode): Type { - Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); - + function checkFunctionExpressionOrObjectLiteralMethod(node: ContextualSignatureNode, checkMode?: CheckMode): Type { // Grammar checking const hasGrammarError = checkGrammarFunctionLikeDeclaration(node); if (!hasGrammarError && node.kind === SyntaxKind.FunctionExpression) { @@ -16585,9 +16579,7 @@ namespace ts { return type; } - function checkFunctionExpressionOrObjectLiteralMethodDeferred(node: ArrowFunction | FunctionExpression | MethodDeclaration) { - Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node)); - + function checkFunctionExpressionOrObjectLiteralMethodDeferred(node: ContextualSignatureNode) { const functionFlags = getFunctionFlags(node); const returnOrPromisedType = node.type && ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async ? @@ -17521,7 +17513,7 @@ namespace ts { return checkExpressionForMutableLocation((<PropertyAssignment>node).initializer, checkMode); } - function checkObjectLiteralMethod(node: MethodDeclaration, checkMode?: CheckMode): Type { + function checkObjectLiteralMethod(node: MethodDeclaration & { parent: ObjectLiteralExpression }, checkMode?: CheckMode): Type { // Grammar checking checkGrammarMethod(node); @@ -17664,7 +17656,7 @@ namespace ts { return checkClassExpression(<ClassExpression>node); case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: - return checkFunctionExpressionOrObjectLiteralMethod(<FunctionExpression>node, checkMode); + return checkFunctionExpressionOrObjectLiteralMethod(<FunctionExpression | ArrowFunction>node, checkMode); case SyntaxKind.TypeOfExpression: return checkTypeOfExpression(<TypeOfExpression>node); case SyntaxKind.TypeAssertionExpression: diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 98efa1f3e53b3..c5329ad7175d7 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -721,6 +721,9 @@ namespace ts { | AccessorDeclaration ; + /** Type of nodes that may have a contextual signature. */ + export type ContextualSignatureNode = FunctionExpression | ArrowFunction | MethodDeclaration & { parent: ObjectLiteralExpression }; + export interface PropertyAssignment extends ObjectLiteralElement { kind: SyntaxKind.PropertyAssignment; name: PropertyName; @@ -2545,6 +2548,7 @@ namespace ts { getAugmentedPropertiesOfType(type: Type): Symbol[]; getRootSymbols(symbol: Symbol): Symbol[]; getContextualType(node: Expression): Type | undefined; + getContextualSignature(node: ContextualSignatureNode): Signature | undefined; getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[]): Signature | undefined; getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature | undefined; isImplementationOfOverload(node: FunctionLikeDeclaration): boolean | undefined; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index a575024870775..368d57addf96b 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -934,7 +934,11 @@ namespace ts { return node && node.kind === SyntaxKind.Block && isFunctionLike(node.parent); } - export function isObjectLiteralMethod(node: Node): node is MethodDeclaration { + export function isContextualSignatureNode(node: Node): node is ContextualSignatureNode { + return node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.ArrowFunction || isObjectLiteralMethod(node); + } + + export function isObjectLiteralMethod(node: Node): node is MethodDeclaration & { parent: ObjectLiteralExpression } { return node && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression; }