The Making of a TypeScript Feature: Inferring Type Predicates
The Making of a TypeScript Feature: Inferring Type Predicates
Effective TypeScript: The Making of a TypeScript Feature: Inferring Type Predicates
https://effectivetypescript.com/2024/04/16/inferring-a-type-predicate/
Absolutely fantastic article 👏👏👏
Great! By the way, the link in There are some notorious examples of this is broken which missing leading h. Currently it's ttps://github.com/microsoft/TypeScript/pull/38839#issuecomment-1160929515
Thanks for the heads up @evan-lc. Should be fixed now.
👏👏👏
👏👏👏
Hi Dan, without having read everything here and on the PR, I'm wondering what's holding back to resolve the non-null of a null conditional boolean member access: devices.filter(x => x?.enabled) is still (Device | null)[], while devices.filter(x => x != null).filter(x => x.enabled) actually results in Device[]. I'm also wondering what's keeping devices.filter(x => x) from ending up as Devices[], I'd assume the predicate is implicitly typed as (Device | null) => Boolean (because filter() expects a predicate), but apparently it's not that simple.
Either way, thanks for implementing this and nice report of the road leading up to this feature.
@mycroes It's because type predicates refine the parameter type in a specific way when they return false, not just true. For x => x?.enabled to be a type predicate (x: Device|null) => x is Device, you'd have to have two things be the case:
- When it returns
true,xwould have to have aDevicetype. (This is the case!) - When it returns
false,xwould have to benull. (This is not the case.)
So this is not a valid type predicate. Take a look at The Hidden Side of Type Predicates
and the Plot Twist section of this post. Of course, this criterion feels overly strict here since filter only cares about the true case. For your examples to work, we'd need one-sided type predicates.