Skip to content

Contextual type doesn't apply to elements of array literal spread into another array literal #45600

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

Open
dmitmel opened this issue Aug 27, 2021 · 2 comments
Labels
Bug A bug in TypeScript Domain: Contextual Types The issue relates to contextual types Effort: Moderate Requires experience with the TypeScript codebase, but feasible. Harder than "Effort: Casual". Help Wanted You can do this
Milestone

Comments

@dmitmel
Copy link

dmitmel commented Aug 27, 2021

Bug Report

πŸ”Ž Search Terms

spread operator, type inference

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

interface Test {
    field: 'a' | 'b' | 'c'
}

let arr: Test[] = [
    { field: 'c' },
    ...[
        { field: 'a' }, // field: string
//        ^?
        { field: 'b' }, // field: string
//        ^?
    ]
]

function test(...args: Test[]): void {}

test(
    { field: 'c' },
    ...[
        { field: 'a' }, // field: string
//        ^?
        { field: 'b' }, // field: string
//        ^?
    ]
)

Workbench Repro

πŸ™ Actual behavior

The types of objects in the array nested through the spread operator is not inferred to be Test, as such inference begins from scratch, so the type of field in those objects becomes string (and is not detected to be 'a' | 'b' | 'c' which I specified in the interface), and a rather cryptic type error is shown:

Type '{ field: string; }' is not assignable to type 'Test'.
  Types of property 'field' are incompatible.
    Type 'string' is not assignable to type '"a" | "b" | "c"'.

I have also included an example with using the spread operator in a function call for completeness, it generates basically the same error.

I'm not sure if this is really a bug, but regardless, it is trivial to work around by just forcing compiler's hand a little by doing this:

let arr: Test[] = [
    { field: 'c' },
    ...[
        { field: 'a' as const },
        { field: 'b' as const },
    ]
]

Which forces the inferred types of the objects to actually be compatible, or assigning the spread array to a variable with an explicitly defined type:

let nested: Test[] = [
    { field: 'a' },
    { field: 'b' },
]
let arr: Test[] = [
    { field: 'c' },
    ...nested
]

πŸ™‚ Expected behavior

I would expect the type of expr3 in [expr1, expr2, ...expr3] to be inferred to be Iterable<T> or something like that provided that we know that the type of elements of the overall array is T. I believe that in my repro it would make types of nested objects to be inferred correctly as Test.

@andrewbranch andrewbranch changed the title Type inference starts all over again for array literals passed to the spread operator Contextual type doesn't apply to elements of array literal spread into another array literal Aug 27, 2021
@andrewbranch
Copy link
Member

Can you show an example of why you'd use a pattern like this in real life? It doesn't seem useful to apply an array spread to an array literal, but I'm sure I'm missing something.

@andrewbranch andrewbranch added the Bug A bug in TypeScript label Sep 1, 2021
@andrewbranch andrewbranch added this to the Backlog milestone Sep 1, 2021
@andrewbranch andrewbranch added Domain: Contextual Types The issue relates to contextual types Effort: Moderate Requires experience with the TypeScript codebase, but feasible. Harder than "Effort: Casual". Help Wanted You can do this labels Sep 1, 2021
@Andarist
Copy link
Contributor

Andarist commented Feb 4, 2023

as to the real-life use case - conditional spreading comes to mind:

interface Test {
  field: "a" | "b" | "c";
}

declare const cond: boolean;

let arr: Test[] = [
  { field: "c" },
  ...(cond ? [{ field: "a" }, { field: "b" }] : []), // currently errors
];

function test(...args: Test[]): void {}

test({ field: "c" }, ...(cond ? [{ field: "a" }, { field: "b" }] : [])); // currently errors

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Domain: Contextual Types The issue relates to contextual types Effort: Moderate Requires experience with the TypeScript codebase, but feasible. Harder than "Effort: Casual". Help Wanted You can do this
Projects
None yet
Development

No branches or pull requests

3 participants