Repository navigation
Inconsistent inferred type predicate for filter #61182
Description
Activity
MartinJohns commented
on Feb 15, 2025 ContributorMore actionsThis is working as intended. Only for specific cases the type guard will be inferred. See #57465, the "Interesting cases" section.
The type guard must be true for all values of the narrowed type, but your second function does not fulfill that purpose. The related issue to tackle this limitation is #15048.
Here's an example of the problem: Playground link
const fn = (x: string | null): x is string => x !== null && x.startsWith('t') declare const value: string | null if (fn(value)) { value; // ^? } if (!fn(value)) { value; // ^? }
In the second if-check the type is narrowed to
null, because the type guard checks if the value is astring- and if it's not it must benull. Note that there's nothing special about the function being passed tofilter.Thanks for your comment Martin Johns (@MartinJohns), I guess the main problem is the "else" of the type inference, as it can still be a string.
I think that
.filter()is indeed a special case, as the "else" inference is irrelevant (it excludes any value that would make the predicate false), but I guess that currently that is not possible given how inferred predicates work.Manual type inference it is then!
const c = a.filter((x): x is string => x !== null && x.startsWith('t'))
MartinJohns commented
on Feb 15, 2025 ContributorMore actionsI think that
.filter()is indeed a special caseThe team (which I'm not part of, just pointing out) does not like to hardcode special cases. This would lead to confusion, as people would expect the same behavior for their own types and implementations. Think of a
filter()function for anObservableimplementation. It would be very confusing if the inference for type guards would work different here from theArray.filter()case.So without #15048 this remains unsolved.
Reacted by Pedro Lamas- addedWorking as IntendedThe behavior described is the intended behavior; this is not a bugThe behavior described is the intended behavior; this is not a bug
on Feb 24, 2025 typescript-bot commented
on Feb 27, 2025 ContributorMore actionsThis issue has been marked as "Working as Intended" and has seen no recent activity. It has been automatically closed for house-keeping purposes.
- locked as resolved and limited conversation to collaborators
on Oct 22, 2025
🔎 Search Terms
filter type predicate
🕗 Version & Regression Information
This only makes sense since TS5.5, when inferred type predicates were introduced.
⏯ Playground Link
https://www.typescriptlang.org/play/?#code/MYewdgzgLgBAhjAvDA2gcigU2mgNDMAVwBtiBdAKAHoqY6YA9AfgotElgCMl4A6AMwCWxLACcAFAA8kAPhjSAhImRFSASmq16zVu2gxgPOAOFips+TCUqSxGADJ783tDiioEAOqCoAC3EYaGoaNPSMLBRAA
💻 Code
🙁 Actual behavior
On the above, the type of
bis correctly inferred asstring[], but the type ofcis incorrectly inferred to(string | null)[]🙂 Expected behavior
The inferred type of
cshouldstring[], just like the inferred type ofb.Additional information about the issue
No response