microsoft / microsoft/TypeScript
[Control flow] Array filter with typeguard works differently following array initial value
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 111k
- Forks
- 14.3k
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 132
Description
🔎 Search Terms
filter + typeguard + control flow + strictNullChecks
🕗 Version & Regression Information
- This is the behavior in every version I tried, and I reviewed the FAQ for entries about filter + typeguards + control flow + strictNullChecks
⏯ Playground Link
💻 Code
const raw: string[] | (string | null)[] = [];
const filtered: string[] = raw.filter((step: string | null): step is string => typeof step === 'string') // KO
// Type '(string | null)[]' is not assignable to type 'string[]'.
const raw: string[] |(string | null)[] = ["plop", null];
const filtered: string[] = raw.filter((step: string | null): step is string => typeof step === 'string') // OK no error
🙁 Actual behavior
There is a strange difference in control flow when you filter nullish values in an array regarding the declaration of that array. This is definitely a edge case. The type string[] | (string | null)[] comes from an union type in my case.
🙂 Expected behavior
No difference and typeguard should work (regardless the fact it is valid).
Additional information about the issue
I first thought it was a regression due to #57465 but I tested it on several version. The issue has always been here. I looked into a lot of issues about typeguards and filters but unfortunately, could not find one similar to my issue 😢
Thanks anyway for the great job
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked TypeScript Playground examples and compare the two declarations of raw: an empty union array versus one initialized with values. Investigate how filter's type predicate is checked for each control-flow path. Done means both examples accept the string[] assignment consistently, with coverage for the demonstrated behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100