Skip to content
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

Function cannot be contextually typed when its rest parameter type is tuple type with leading rest elements #45972

Open
uhyo opened this issue Sep 20, 2021 · 4 comments · May be fixed by #49218
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@uhyo
Copy link
Contributor

uhyo commented Sep 20, 2021

Bug Report

🔎 Search Terms

function rest arguments parameter tuple type leading middle rest elements

🕗 Version & Regression Information

4.2.3, 4.3.5, 4.4.2

  • I was unable to test this on prior versions because leading rest elements in tuple types were introduced in TS 4.2

⏯ Playground Link

Playground link with relevant code

💻 Code

type Func = (...args: [...strs: string[], num1: number, num2: number]) => void

// OK
const func: Func = () => {}
// Error:
// Type '(arg1: string | number) => void' is not assignable to type 'Func'.
//  Types of parameters 'arg1' and 'strs' are incompatible.
//    Type '[...strs: string[], num1: number, num2: number]' is not assignable to type '[arg1: string | number]'.
//      Source has 2 element(s) but target allows only 1.
const func1: Func = (arg1) => {}

// Error:
// Type '(arg2: string | number, arg3: string | number) => void' is not assignable to type 'Func'.
//   Types of parameters 'arg2' and 'strs' are incompatible.
//     Type '[...strs: string[], num1: number, num2: number]' is not assignable to type '[arg2: string | number, arg3: string | number]'.
//       Target allows only 2 element(s) but source may have more.
const func2: Func = (arg2, arg3) => {};

// Error:
// Type '(arg4: string | number, arg5: string | number, arg6: string | number) => void' is not assignable to type 'Func'.
//   Types of parameters 'arg4' and 'strs' are incompatible.
//     Type '[...strs: string[], num1: number, num2: number]' is not assignable to type '[arg4: string | number, arg5: string | number, arg6: string | number]'.
//       Target requires 3 element(s) but source may have fewer.
const func3: Func = (arg4, arg5, arg6) => {};

🙁 Actual behavior

Functions that have one or more arguments (func1, func2, func3) cannot be assigned to variables of type Func.

🙂 Expected behavior

No compiler errors and the types of arguments are inferred as:

  • arg1, arg2, arg3, arg4, arg5: string | number
  • arg6: string | number | undefined
@jcalz
Copy link
Contributor

jcalz commented Sep 20, 2021

Assuming we want to support such assignments, I think you don't want

  • arg6: string | number
  • arg4: string

If func3 is a Func then you should be able to call func3(1, 2), so arg4 should be string | number while arg6 should be string | number | undefined.

@uhyo
Copy link
Contributor Author

uhyo commented Sep 21, 2021

Thank you for pointing out 😃 you're right, I updated my issue comment.

@graphemecluster
Copy link
Contributor

graphemecluster commented May 29, 2022

Although we can wrap all the arguments inside a tuple with rest syntax as a workaround, the type of arg6 is inferred incorrectly to string | number, which lacks undefined:

type Func = (...args: [...strs: string[], num1: number, num2: number]) => void

const func: Func = () => {}

const func1: Func = (...[arg1]) => {}

const func2: Func = (...[arg2, arg3]) => {};

const func3: Func = (...[arg4, arg5, arg6]) => {};

Playground link with the above code


Edit: The above code works because the arguments are being inferred as a whole. Adding types makes it break:

type Func = (...args: [...strs: string[], num1: number, num2: number]) => void

// OK
const func: Func = () => {}
// Error:
// Type '(__0_0: string | number) => void' is not assignable to type 'Func'.
//   Types of parameters '__0_0' and 'strs' are incompatible.
//     Type '[...strs: string[], num1: number, num2: number]' is not assignable to type '[string | number]'.
//       Source has 2 element(s) but target allows only 1.
const func1: Func = (...[arg1]: [string | number]) => {}
// Error:
// Type '(__0_0: string | number, __0_1: string | number) => void' is not assignable to type 'Func'.
//   Types of parameters '__0_0' and 'strs' are incompatible.
//     Type '[...strs: string[], num1: number, num2: number]' is not assignable to type '[string | number, string | number]'.
//       Target allows only 2 element(s) but source may have more.
const func2: Func = (...[arg2, arg3]: [string | number, string | number]) => {};
// Error:
// Type '(__0_0: string | number, __0_1: string | number, __0_2: string | number | undefined) => void' is not assignable to type 'Func'.
//   Types of parameters '__0_0' and 'strs' are incompatible.
//     Type '[...strs: string[], num1: number, num2: number]' is not assignable to type '[string | number, string | number, string | number | undefined]'.
//       Target requires 3 element(s) but source may have fewer.
const func3: Func = (...[arg4, arg5, arg6]: [string | number, string | number, string | number | undefined]) => {};

Playground link with the above code

In any case, this issue should be a bug, not a suggestion.

Andarist added a commit to Andarist/TypeScript that referenced this issue Dec 28, 2022
@Andarist
Copy link
Contributor

I'm fixing the primary problem reported in this issue here: #49218 .

That PR doesn't solve the missing | undefined problem though. I think this is a separate discussion and should be handled in a separate PR. In fact, this problem has its own dedicated issue: #46063 (also reported by @uhyo )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants