Skip to content

"Target requires x element(s) but source may have fewer." despite filter by lengthΒ #62422

Closed as not planned

Description

@Sainan

πŸ”Ž Search Terms

Target requires element(s) but source may have fewer, filter, length

πŸ•— Version & Regression Information

Not a regression

⏯ Playground Link

https://www.typescriptlang.org/play/?#code/MYewdgzgLgBAhgJwQLhtBBLMBzA2gXRgF4ZcYAiOAI2HIBoKATAUwDN6LtnyZ8BuAFChIsKJmwI4AWwipc6LNgYKcysYvwFi8JADopcAA4AKAB7EAfDFO6IhgDYYox8uQCUb3awz2ozBGaW1rr2zDhQABbEJADMboLCECChISDYxuoS0hDxAkA

πŸ’» Code

const arr: string[] = [ "abc", "def", "ge" ];
const trigrams: [string, string, string][] = arr.map(x => x.split("")).filter(x => x.length == 3);
console.log(trigrams);

πŸ™ Actual behavior

    Type 'string[][]' is not assignable to type '[string, string, string][]'.
      Type 'string[]' is not assignable to type '[string, string, string]'.
        Target requires 3 element(s) but source may have fewer.

πŸ™‚ Expected behavior

No type error

Additional information about the issue

No response

Activity

  1. jcalz commented on Sep 9, 2025

    @jcalz
    Contributor

    note: not a TS team member, ignore me if you want

    TS does not treat checking length as a type guard on array types that aren't already (unions of) tuples. This isn't a bug; everything is behaving as intended and as designed. It's more of a limitation or missing feature. Maybe it's a duplicate of #28337.

    As a workaround you can always tell TS that x => x.length == 3 behaves as a type guard, like so:

    arr.map(x => x.split("")).filter((x): x is [string, string, string] => x.length == 3); 

    Playground link

  2. Sainan commented on Sep 9, 2025

    @Sainan
    ContributorAuthor

    Well, it can be done shorter :^)

    arr.map(x => x.split("")).filter(x => x.length == 3).map(x => [ x[0], x[1], x[2] ]);

    Playground link

    But the point is that this is unexpected. It's not like a major issue, but definitely something that "could be improved."

  3. RyanCavanaugh commented on Sep 9, 2025

    @RyanCavanaugh
    Member

    We don't really have a good way to implement this. Even intersecting in a { length: 3 } property (which even by itself is suspect in terms of downstream effects), that's not enough to turn a string[] into a [string, string, string]

  4. jcalz commented on Sep 9, 2025

    @jcalz
    Contributor

    it can be done shorter

    The point wasn't to code-golf, it was to show how you could tell TS that the filter callback was meant to act as a type guard, without changing the emitted JS at all.

  5. Sainan commented on Sep 9, 2025

    @Sainan
    ContributorAuthor

    I know. My point was just to show that .map can help it see the type conversion since indexing a string[] is seen as producing string by default.

  6. typescript-bot commented on Sep 12, 2025

    @typescript-bot
    Contributor

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

  7. Sainan commented on Sep 12, 2025

    @Sainan
    ContributorAuthor

    Can .filter(x => x.length == 3) really not be implied to be the same as .map(x => [ x[0], x[1], x[2] ]) ?

  8. RyanCavanaugh commented on Sep 12, 2025

    @RyanCavanaugh
    Member

    We're not really willing to add special-case magic like that to the type system. If something can't be implemented in a way that's general-purpose, it's generally not done at all

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

    Design LimitationConstraints of the existing architecture prevent this from being fixed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions