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

Array concat has wrong types #47351

Open
ljharb opened this issue Jan 8, 2022 · 10 comments
Open

Array concat has wrong types #47351

ljharb opened this issue Jan 8, 2022 · 10 comments
Labels
Bug A bug in TypeScript Domain: lib.d.ts The issue relates to the different libraries shipped with TypeScript Help Wanted You can do this
Milestone

Comments

@ljharb
Copy link
Contributor

ljharb commented Jan 8, 2022

Bug Report

A not-uncommon JS idiom is [].concat(x || [], y || [], z || []) as a faster, simpler, more backwards-compatible [x, y, z].flatMap(x => x || []). However, when I try, I get type errors.

🔎 Search Terms

array concat
concat overload

🕗 Version & Regression Information

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

⏯ Playground Link

Playground link with relevant code

💻 Code

const a = [].concat(
    true ? 'a' : [],
    false ? 'b' : [],
);

const x = [].concat(
    false ? 'b' : [],
    true ? 'a' : [],
);

🙁 Actual behavior

No overload matches this call.
  Overload 1 of 2, '(...items: ConcatArray<never>[]): never[]', gave the following error.
    Argument of type 'never[] | "a"' is not assignable to parameter of type 'ConcatArray<never>'.
      Type 'string' is not assignable to type 'ConcatArray<never>'.
  Overload 2 of 2, '(...items: ConcatArray<never>[]): never[]', gave the following error.
    Argument of type 'never[] | "a"' is not assignable to parameter of type 'ConcatArray<never>'.
      Type 'string' is not assignable to type 'ConcatArray<never>'.(2769)

🙂 Expected behavior

No type errors (except perhaps that the variable may be any until i provide an explicit type for the resulting array), because this is valid JavaScript since at least ES3.

@ajafff
Copy link
Contributor

ajafff commented Jan 8, 2022

As a workaround you can use new Array<string>().concat( true ? 'a' : [], false ? 'b' : [])

@ljharb
Copy link
Contributor Author

ljharb commented Jan 8, 2022

That would create a sparse array, which is deoptimized in engines, so that would never be a good workaround (new Array should never, ever be used).

@MartinJohns
Copy link
Contributor

([] as string[]) works as well to help the type-checker.

@MartinJohns
Copy link
Contributor

MartinJohns commented Jan 8, 2022

Duplicate of #36554 (comment). Used search terms: never array concat

@ljharb
Copy link
Contributor Author

ljharb commented Jan 8, 2022

Thanks for the workaround suggestion! Unfortunately that doesn’t help me in JS, using JSDoc.

@fatcerberus
Copy link

Your examples work as-is for me in JS, even with checkJs on; that said, the equivalent JSDoc-based workaround would be

const a = /** @type {string[]} */ ([]).concat(
    true ? 'a' : [],
    false ? 'b' : [],
);

But this won't work in a .ts file (or your playground) because JSDoc isn't used for typing there.

@MartinJohns
Copy link
Contributor

@fatcerberus The examples don't work with strictNullChecks enabled. The playground strangely turns this flag off when you switch to JS mode, I fell for it the first time as well.

@SancheZz
Copy link

SancheZz commented Jan 9, 2022

@ljharb you can use spread operator instead of the concat method as a workaround.

@MartinJohns
Copy link
Contributor

@SancheZz He's intentionally not using the spread operator. See his first sentence, where he mentions:

more backwards-compatible

@ljharb
Copy link
Contributor Author

ljharb commented Jan 9, 2022

Also, spread has different semantics - a string is spread into code units, a Map into entries, a Set into values, but the precise semantic I want here is IsConcatSpreadable, which only concat, flat, and flatMap have.

@RyanCavanaugh RyanCavanaugh added Bug A bug in TypeScript Domain: lib.d.ts The issue relates to the different libraries shipped with TypeScript Help Wanted You can do this labels Jan 11, 2022
@RyanCavanaugh RyanCavanaugh added this to the Backlog milestone Jan 11, 2022
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: lib.d.ts The issue relates to the different libraries shipped with TypeScript Help Wanted You can do this
Projects
None yet
Development

No branches or pull requests

6 participants