TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

Inconsistency with Rest Parameter in Function Type

Open nlipiarski opened this issue 1 year ago • 2 comments

🔎 Search Terms

rest parameters, parameter list, function parameters

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about parameters and rest parameters

⏯ Playground Link

https://www.typescriptlang.org/play/?ts=5.4.5&ssl=5&ssc=12&pln=1&pc=1#code/C4TwDgpgBAysBOBLAdgcwGIFdkGNiIHtkoBeKACgDpqBDeVAZwC4oGEVUBtAXQEpSAfFABuBRABMA3AChpOImygQAHjQC2YADYQAjCzhI0WXPiKkKdVHtbs0-EkPnIGBbZU0FU5SzvcQ0wAAWvDLSKupauuQhQA

💻 Code

type StringFunction = (...args: string[]) => void;

const example1: StringFunction = (arg1: string) => console.log(arg1.length);

example1();

🙁 Actual behavior

This code does not display any type errors on any of the versions I tried, but will break at run time on the example1() call.

🙂 Expected behavior

Typescript should prevent the assignment of (arg1: string) => void to a variable of type (...args: string[]) => void since it is possible to have args be empty.

Additional information about the issue

I attempted to search for other issues related to this and came up empty handed. This is different from the "I'm allowed to use a shorter parameter list where a longer one is expected" issue which has drowned out a lot of my searching.

Thanks in advance for any help with this.

nlipiarski avatar May 16 '24 16:05 nlipiarski

I found this in the existing tests: https://github.com/microsoft/TypeScript/blob/79a851426c514a12a75b342e8dd2460ee6615f73/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithCallSignaturesWithRestParameters.ts#L16

This is a pretty old test though and it assumes strictNullChecks: false. I think it doesn't quite make sense in the strict world for this to be allowed. Rest params are effectively optional so why do we observe a difference here?

// error
const fn1: (a?: string) => void = (a: string) => {}

// ok?
const fn2: (...args: number[]) => void = (x: number) => {};

We can find some recent tests with strict: true that would break if the above wouldn't work: https://github.com/microsoft/TypeScript/blob/79a851426c514a12a75b342e8dd2460ee6615f73/tests/cases/compiler/assignmentToAnyArrayRestParameters.ts#L6-L14

At the very least f2 and f4 should error here - assuming that the issue at hand would get fixed.

Andarist avatar May 17 '24 07:05 Andarist

rest param corresponds to infinite number of params

Yeah, no. It can be up to an infinite number of params, but a minimum of zero. i.e. the same reason fn1 is an error in your example.

I guess the reasoning here is the same as how an object with a string index signature is treated in some contexts as having all possible properties at once, which is only rectified by enabling noUncheckedIndexedAccess.

fatcerberus avatar May 17 '24 15:05 fatcerberus

This is an intentional affordance for functions like Regex#replace or (throwback) AMD's define call.

In practice any time you alias a function into a position with rest args, the number of arguments you'll get is almost always determinable at the call site (e.g. by the number of groups in the regex, the number of module names passed to define, and so on)

RyanCavanaugh avatar Jun 14 '24 21:06 RyanCavanaugh

I could swear we discussed this on GitHub (not CodePlex) but I can't find it - very hard to search for

RyanCavanaugh avatar Jun 14 '24 21:06 RyanCavanaugh

This issue has been marked as "Working as Intended" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

typescript-bot avatar Jun 17 '24 01:06 typescript-bot