Skip to content

Expose getContextualSignature #16024

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 20 additions & 28 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 ?
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 5 additions & 1 deletion src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down