镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

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

Description

@uhyo

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

Activity

  1. jcalz commented on Sep 20, 2021

    @jcalz
    Contributor

    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.

  2. uhyo commented on Sep 21, 2021

    @uhyo
    ContributorAuthor

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

  3. graphemecluster commented on May 29, 2022

    @graphemecluster
    Contributor

    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.

  4. Andarist commented on Dec 29, 2022

    @Andarist
    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 (@uhyo) )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Awaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions