mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-30 01:04:49 -05:00
Fix type when annotated with a JSDoc function type (#22692)
* Fix type when annotated with a JSDoc function type Previously, 1. A variable annotated with a JSDoc function type would not require all its parameters to be provided. This should only apply to functions without a type annotation. 2. A parameter in a function with a JSDoc function type annotation would still have the type 'any'. 3. Two `var` declarations in a Typescript and Javascript file, respectively, would error even when they had identical function types. * Update baselines and add constructor test * Handle ConstructorType too * Add test:method sig inside literal type * Contextually type parameters by parent sig's JSDoc Instead of a syntactic check in getJSDocTag * Remove redundant check:isUntypedSignatureInJSFile * Positive check for value signatures Instead of excluding type signatures piecemeal.
This commit is contained in:
committed by
GitHub
parent
d88041fc0a
commit
b56093f3ac
@@ -6691,7 +6691,11 @@ namespace ts {
|
||||
let hasThisParameter: boolean;
|
||||
const iife = getImmediatelyInvokedFunctionExpression(declaration);
|
||||
const isJSConstructSignature = isJSDocConstructSignature(declaration);
|
||||
const isUntypedSignatureInJSFile = !iife && !isJSConstructSignature && isInJavaScriptFile(declaration) && !hasJSDocParameterTags(declaration);
|
||||
const isUntypedSignatureInJSFile = !iife &&
|
||||
isInJavaScriptFile(declaration) &&
|
||||
isValueSignatureDeclaration(declaration) &&
|
||||
!hasJSDocParameterTags(declaration) &&
|
||||
!getJSDocType(declaration);
|
||||
|
||||
// If this is a JSDoc construct signature, then skip the first parameter in the
|
||||
// parameter list. The first parameter represents the return type of the construct
|
||||
@@ -9100,7 +9104,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
function isContextSensitiveFunctionOrObjectLiteralMethod(func: Node): func is FunctionExpression | ArrowFunction | MethodDeclaration {
|
||||
return (isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func)) && isContextSensitiveFunctionLikeDeclaration(func);
|
||||
return (isInJavaScriptFile(func) && isFunctionDeclaration(func) || isFunctionExpressionOrArrowFunction(func) || isObjectLiteralMethod(func)) &&
|
||||
isContextSensitiveFunctionLikeDeclaration(func);
|
||||
}
|
||||
|
||||
function getTypeWithoutSignatures(type: Type): Type {
|
||||
@@ -14168,49 +14173,49 @@ namespace ts {
|
||||
// Return contextual type of parameter or undefined if no contextual type is available
|
||||
function getContextuallyTypedParameterType(parameter: ParameterDeclaration): Type | undefined {
|
||||
const func = parameter.parent;
|
||||
if (isContextSensitiveFunctionOrObjectLiteralMethod(func)) {
|
||||
const iife = getImmediatelyInvokedFunctionExpression(func);
|
||||
if (iife && iife.arguments) {
|
||||
const indexOfParameter = func.parameters.indexOf(parameter);
|
||||
if (parameter.dotDotDotToken) {
|
||||
const restTypes: Type[] = [];
|
||||
for (let i = indexOfParameter; i < iife.arguments.length; i++) {
|
||||
restTypes.push(getWidenedLiteralType(checkExpression(iife.arguments[i])));
|
||||
}
|
||||
return restTypes.length ? createArrayType(getUnionType(restTypes)) : undefined;
|
||||
if (!isContextSensitiveFunctionOrObjectLiteralMethod(func)) {
|
||||
return undefined;
|
||||
}
|
||||
const iife = getImmediatelyInvokedFunctionExpression(func);
|
||||
if (iife && iife.arguments) {
|
||||
const indexOfParameter = func.parameters.indexOf(parameter);
|
||||
if (parameter.dotDotDotToken) {
|
||||
const restTypes: Type[] = [];
|
||||
for (let i = indexOfParameter; i < iife.arguments.length; i++) {
|
||||
restTypes.push(getWidenedLiteralType(checkExpression(iife.arguments[i])));
|
||||
}
|
||||
const links = getNodeLinks(iife);
|
||||
const cached = links.resolvedSignature;
|
||||
links.resolvedSignature = anySignature;
|
||||
const type = indexOfParameter < iife.arguments.length ?
|
||||
getWidenedLiteralType(checkExpression(iife.arguments[indexOfParameter])) :
|
||||
parameter.initializer ? undefined : undefinedWideningType;
|
||||
links.resolvedSignature = cached;
|
||||
return type;
|
||||
return restTypes.length ? createArrayType(getUnionType(restTypes)) : undefined;
|
||||
}
|
||||
const links = getNodeLinks(iife);
|
||||
const cached = links.resolvedSignature;
|
||||
links.resolvedSignature = anySignature;
|
||||
const type = indexOfParameter < iife.arguments.length ?
|
||||
getWidenedLiteralType(checkExpression(iife.arguments[indexOfParameter])) :
|
||||
parameter.initializer ? undefined : undefinedWideningType;
|
||||
links.resolvedSignature = cached;
|
||||
return type;
|
||||
}
|
||||
const contextualSignature = getContextualSignature(func);
|
||||
if (contextualSignature) {
|
||||
const funcHasRestParameters = hasRestParameter(func);
|
||||
const len = func.parameters.length - (funcHasRestParameters ? 1 : 0);
|
||||
let indexOfParameter = func.parameters.indexOf(parameter);
|
||||
if (getThisParameter(func) !== undefined && !contextualSignature.thisParameter) {
|
||||
Debug.assert(indexOfParameter !== 0); // Otherwise we should not have called `getContextuallyTypedParameterType`.
|
||||
indexOfParameter -= 1;
|
||||
}
|
||||
const contextualSignature = getContextualSignature(func);
|
||||
if (contextualSignature) {
|
||||
const funcHasRestParameters = hasRestParameter(func);
|
||||
const len = func.parameters.length - (funcHasRestParameters ? 1 : 0);
|
||||
let indexOfParameter = func.parameters.indexOf(parameter);
|
||||
if (getThisParameter(func) !== undefined && !contextualSignature.thisParameter) {
|
||||
Debug.assert(indexOfParameter !== 0); // Otherwise we should not have called `getContextuallyTypedParameterType`.
|
||||
indexOfParameter -= 1;
|
||||
}
|
||||
|
||||
if (indexOfParameter < len) {
|
||||
return getTypeAtPosition(contextualSignature, indexOfParameter);
|
||||
}
|
||||
if (indexOfParameter < len) {
|
||||
return getTypeAtPosition(contextualSignature, indexOfParameter);
|
||||
}
|
||||
|
||||
// If last parameter is contextually rest parameter get its type
|
||||
if (funcHasRestParameters &&
|
||||
indexOfParameter === (func.parameters.length - 1) &&
|
||||
isRestParameterIndex(contextualSignature, func.parameters.length - 1)) {
|
||||
return getTypeOfSymbol(lastOrUndefined(contextualSignature.parameters));
|
||||
}
|
||||
// If last parameter is contextually rest parameter get its type
|
||||
if (funcHasRestParameters &&
|
||||
indexOfParameter === (func.parameters.length - 1) &&
|
||||
isRestParameterIndex(contextualSignature, func.parameters.length - 1)) {
|
||||
return getTypeOfSymbol(lastOrUndefined(contextualSignature.parameters));
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// In a variable, parameter or property declaration with a type annotation,
|
||||
@@ -14773,7 +14778,16 @@ namespace ts {
|
||||
// union type of return types from these signatures
|
||||
function getContextualSignature(node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature {
|
||||
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node));
|
||||
const type = getContextualTypeForFunctionLikeDeclaration(node);
|
||||
let type: Type;
|
||||
if (isInJavaScriptFile(node)) {
|
||||
const jsdoc = getJSDocType(node);
|
||||
if (jsdoc) {
|
||||
type = getTypeFromTypeNode(jsdoc);
|
||||
}
|
||||
}
|
||||
if (!type) {
|
||||
type = getContextualTypeForFunctionLikeDeclaration(node);
|
||||
}
|
||||
if (!type) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -1958,6 +1958,18 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
export type ValueSignatureDeclaration =
|
||||
| FunctionDeclaration
|
||||
| MethodDeclaration
|
||||
| ConstructorDeclaration
|
||||
| AccessorDeclaration
|
||||
| FunctionExpression
|
||||
| ArrowFunction;
|
||||
|
||||
export function isValueSignatureDeclaration(node: Node): node is ValueSignatureDeclaration {
|
||||
return isFunctionExpression(node) || isArrowFunction(node) || isMethodOrAccessor(node) || isFunctionDeclaration(node) || isConstructorDeclaration(node);
|
||||
}
|
||||
|
||||
function walkUp(node: Node, kind: SyntaxKind) {
|
||||
while (node && node.kind === kind) {
|
||||
node = node.parent;
|
||||
|
||||
Reference in New Issue
Block a user