mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 16:38:05 -06:00
Handle JS synthetic rest args in contextual parameter assignment (#48263)
* Handle JS synthetic rest args in contextual parameter assignment * Limit fixing to only unannotated js rest parameters * Minimize test * Add annotated version * Remove explicit CheckFlags.RestParameter check since apparently not all rest parameters are CheckFlags.RestParameter
This commit is contained in:
parent
92bc2ddc3c
commit
7f652509b6
@ -12862,7 +12862,19 @@ namespace ts {
|
||||
p.typeExpression && isJSDocVariadicType(p.typeExpression.type) ? p.typeExpression.type : undefined);
|
||||
|
||||
const syntheticArgsSymbol = createSymbol(SymbolFlags.Variable, "args" as __String, CheckFlags.RestParameter);
|
||||
syntheticArgsSymbol.type = lastParamVariadicType ? createArrayType(getTypeFromTypeNode(lastParamVariadicType.type)) : anyArrayType;
|
||||
if (lastParamVariadicType) {
|
||||
// Parameter has effective annotation, lock in type
|
||||
syntheticArgsSymbol.type = createArrayType(getTypeFromTypeNode(lastParamVariadicType.type));
|
||||
}
|
||||
else {
|
||||
// Parameter has no annotation
|
||||
// By using a `DeferredType` symbol, we allow the type of this rest arg to be overriden by contextual type assignment so long as its type hasn't been
|
||||
// cached by `getTypeOfSymbol` yet.
|
||||
syntheticArgsSymbol.checkFlags |= CheckFlags.DeferredType;
|
||||
syntheticArgsSymbol.deferralParent = neverType;
|
||||
syntheticArgsSymbol.deferralConstituents = [anyArrayType];
|
||||
syntheticArgsSymbol.deferralWriteConstituents = [anyArrayType];
|
||||
}
|
||||
if (lastParamVariadicType) {
|
||||
// Replace the last parameter with a rest parameter.
|
||||
parameters.pop();
|
||||
@ -32163,7 +32175,12 @@ namespace ts {
|
||||
if (signatureHasRestParameter(signature)) {
|
||||
// parameter might be a transient symbol generated by use of `arguments` in the function body.
|
||||
const parameter = last(signature.parameters);
|
||||
if (isTransientSymbol(parameter) || !getEffectiveTypeAnnotationNode(parameter.valueDeclaration as ParameterDeclaration)) {
|
||||
if (parameter.valueDeclaration
|
||||
? !getEffectiveTypeAnnotationNode(parameter.valueDeclaration as ParameterDeclaration)
|
||||
// a declarationless parameter may still have a `.type` already set by its construction logic
|
||||
// (which may pull a type from a jsdoc) - only allow fixing on `DeferredType` parameters with a fallback type
|
||||
: !!(getCheckFlags(parameter) & CheckFlags.DeferredType)
|
||||
) {
|
||||
const contextualParameterType = getRestTypeAtPosition(context, len);
|
||||
assignParameterType(parameter, contextualParameterType);
|
||||
}
|
||||
@ -32182,9 +32199,9 @@ namespace ts {
|
||||
function assignParameterType(parameter: Symbol, type?: Type) {
|
||||
const links = getSymbolLinks(parameter);
|
||||
if (!links.type) {
|
||||
const declaration = parameter.valueDeclaration as ParameterDeclaration;
|
||||
links.type = type || getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true);
|
||||
if (declaration.name.kind !== SyntaxKind.Identifier) {
|
||||
const declaration = parameter.valueDeclaration as ParameterDeclaration | undefined;
|
||||
links.type = type || (declaration ? getWidenedTypeForVariableLikeDeclaration(declaration, /*reportErrors*/ true) : getTypeOfSymbol(parameter));
|
||||
if (declaration && declaration.name.kind !== SyntaxKind.Identifier) {
|
||||
// if inference didn't come up with anything but unknown, fall back to the binding pattern if present.
|
||||
if (links.type === unknownType) {
|
||||
links.type = getTypeFromBindingPattern(declaration.name);
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
tests/cases/compiler/index.js(3,28): error TS8029: JSDoc '@param' tag has name 'rest', but there is no parameter with that name. It would match 'arguments' if it had an array type.
|
||||
|
||||
|
||||
==== tests/cases/compiler/index.js (1 errors) ====
|
||||
self.importScripts = (function (importScripts) {
|
||||
/**
|
||||
* @param {...unknown} rest
|
||||
~~~~
|
||||
!!! error TS8029: JSDoc '@param' tag has name 'rest', but there is no parameter with that name. It would match 'arguments' if it had an array type.
|
||||
*/
|
||||
return function () {
|
||||
return importScripts.apply(this, arguments);
|
||||
};
|
||||
})(importScripts);
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
=== tests/cases/compiler/index.js ===
|
||||
self.importScripts = (function (importScripts) {
|
||||
>self.importScripts : Symbol(importScripts, Decl(lib.webworker.importscripts.d.ts, --, --))
|
||||
>self : Symbol(self, Decl(lib.dom.d.ts, --, --), Decl(index.js, 0, 0))
|
||||
>importScripts : Symbol(importScripts, Decl(lib.webworker.importscripts.d.ts, --, --))
|
||||
>importScripts : Symbol(importScripts, Decl(index.js, 0, 32))
|
||||
|
||||
/**
|
||||
* @param {...unknown} rest
|
||||
*/
|
||||
return function () {
|
||||
return importScripts.apply(this, arguments);
|
||||
>importScripts.apply : Symbol(Function.apply, Decl(lib.es5.d.ts, --, --))
|
||||
>importScripts : Symbol(importScripts, Decl(index.js, 0, 32))
|
||||
>apply : Symbol(Function.apply, Decl(lib.es5.d.ts, --, --))
|
||||
>arguments : Symbol(arguments)
|
||||
|
||||
};
|
||||
})(importScripts);
|
||||
>importScripts : Symbol(importScripts, Decl(lib.webworker.importscripts.d.ts, --, --))
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
=== tests/cases/compiler/index.js ===
|
||||
self.importScripts = (function (importScripts) {
|
||||
>self.importScripts = (function (importScripts) { /** * @param {...unknown} rest */ return function () { return importScripts.apply(this, arguments); };})(importScripts) : (...args: unknown[]) => any
|
||||
>self.importScripts : (...urls: string[]) => void
|
||||
>self : Window & typeof globalThis
|
||||
>importScripts : (...urls: string[]) => void
|
||||
>(function (importScripts) { /** * @param {...unknown} rest */ return function () { return importScripts.apply(this, arguments); };})(importScripts) : (...args: unknown[]) => any
|
||||
>(function (importScripts) { /** * @param {...unknown} rest */ return function () { return importScripts.apply(this, arguments); };}) : (importScripts: (...urls: string[]) => void) => (...args: unknown[]) => any
|
||||
>function (importScripts) { /** * @param {...unknown} rest */ return function () { return importScripts.apply(this, arguments); };} : (importScripts: (...urls: string[]) => void) => (...args: unknown[]) => any
|
||||
>importScripts : (...urls: string[]) => void
|
||||
|
||||
/**
|
||||
* @param {...unknown} rest
|
||||
*/
|
||||
return function () {
|
||||
>function () { return importScripts.apply(this, arguments); } : (...args: unknown[]) => any
|
||||
|
||||
return importScripts.apply(this, arguments);
|
||||
>importScripts.apply(this, arguments) : any
|
||||
>importScripts.apply : (this: Function, thisArg: any, argArray?: any) => any
|
||||
>importScripts : (...urls: string[]) => void
|
||||
>apply : (this: Function, thisArg: any, argArray?: any) => any
|
||||
>this : any
|
||||
>arguments : IArguments
|
||||
|
||||
};
|
||||
})(importScripts);
|
||||
>importScripts : (...urls: string[]) => void
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
=== tests/cases/compiler/index.js ===
|
||||
self.importScripts = (function (importScripts) {
|
||||
>self.importScripts : Symbol(importScripts, Decl(lib.webworker.importscripts.d.ts, --, --))
|
||||
>self : Symbol(self, Decl(lib.dom.d.ts, --, --), Decl(index.js, 0, 0))
|
||||
>importScripts : Symbol(importScripts, Decl(lib.webworker.importscripts.d.ts, --, --))
|
||||
>importScripts : Symbol(importScripts, Decl(index.js, 0, 32))
|
||||
|
||||
return function () {
|
||||
return importScripts.apply(this, arguments);
|
||||
>importScripts.apply : Symbol(Function.apply, Decl(lib.es5.d.ts, --, --))
|
||||
>importScripts : Symbol(importScripts, Decl(index.js, 0, 32))
|
||||
>apply : Symbol(Function.apply, Decl(lib.es5.d.ts, --, --))
|
||||
>arguments : Symbol(arguments)
|
||||
|
||||
};
|
||||
})(importScripts);
|
||||
>importScripts : Symbol(importScripts, Decl(lib.webworker.importscripts.d.ts, --, --))
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
=== tests/cases/compiler/index.js ===
|
||||
self.importScripts = (function (importScripts) {
|
||||
>self.importScripts = (function (importScripts) { return function () { return importScripts.apply(this, arguments); };})(importScripts) : (...args: string[]) => any
|
||||
>self.importScripts : (...urls: string[]) => void
|
||||
>self : Window & typeof globalThis
|
||||
>importScripts : (...urls: string[]) => void
|
||||
>(function (importScripts) { return function () { return importScripts.apply(this, arguments); };})(importScripts) : (...args: string[]) => any
|
||||
>(function (importScripts) { return function () { return importScripts.apply(this, arguments); };}) : (importScripts: (...urls: string[]) => void) => (...args: string[]) => any
|
||||
>function (importScripts) { return function () { return importScripts.apply(this, arguments); };} : (importScripts: (...urls: string[]) => void) => (...args: string[]) => any
|
||||
>importScripts : (...urls: string[]) => void
|
||||
|
||||
return function () {
|
||||
>function () { return importScripts.apply(this, arguments); } : (...args: string[]) => any
|
||||
|
||||
return importScripts.apply(this, arguments);
|
||||
>importScripts.apply(this, arguments) : any
|
||||
>importScripts.apply : (this: Function, thisArg: any, argArray?: any) => any
|
||||
>importScripts : (...urls: string[]) => void
|
||||
>apply : (this: Function, thisArg: any, argArray?: any) => any
|
||||
>this : any
|
||||
>arguments : IArguments
|
||||
|
||||
};
|
||||
})(importScripts);
|
||||
>importScripts : (...urls: string[]) => void
|
||||
|
||||
12
tests/cases/compiler/noParameterReassignmentIIFEAnnotated.ts
Normal file
12
tests/cases/compiler/noParameterReassignmentIIFEAnnotated.ts
Normal file
@ -0,0 +1,12 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noEmit: true
|
||||
// @filename: index.js
|
||||
self.importScripts = (function (importScripts) {
|
||||
/**
|
||||
* @param {...unknown} rest
|
||||
*/
|
||||
return function () {
|
||||
return importScripts.apply(this, arguments);
|
||||
};
|
||||
})(importScripts);
|
||||
9
tests/cases/compiler/noParameterReassignmentJSIIFE.ts
Normal file
9
tests/cases/compiler/noParameterReassignmentJSIIFE.ts
Normal file
@ -0,0 +1,9 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @noEmit: true
|
||||
// @filename: index.js
|
||||
self.importScripts = (function (importScripts) {
|
||||
return function () {
|
||||
return importScripts.apply(this, arguments);
|
||||
};
|
||||
})(importScripts);
|
||||
Loading…
x
Reference in New Issue
Block a user