Great article, thanks for writing it! I had a quick question:
Whilst an aliased conditional expression on a destructured field will allow for narrowing the original object's type, the flow analysis cannot narrow the type of a destructured sibling.
I'm not sure I understand this point. What do type predicates on foo do to the inferred type of bar in these cases?
I definitely under explained this point... currently no type predicates on foo can act on the inferred type of bar.
In your example, bar will always be number | boolean, regardless.
However, type predicates on foocan influence the inferred type of baz, provided it's available in scope. Hence the differentiation between destructuring in the function signature rather than in the body: in the former there's no baz to influence.
I'm glad you raised this point because I realised I didn't know exactly how type narrowing works for object unions!
Your playground is a good example - I'd intuitively assume that the type of foo or bar could be used to differentiate which part of the union baz happens to be.
That actually doesn't work, which surprised me.
So you either have to add an extra property to one of the unions, e.g.
if('qux'inbaz){...
which defeats the point of destructuring, or by changing one of the fields to be a discriminant.
Discriminants must be a common property of the union where each type is a literal.
Here's a version of your playground where foo is now a discriminant, and baz is now influenced by a condition on foo.
There's three types of literal types: strings, numbers and booleans.
I wonder if it'd be useful if there was a prefix keyword to indicate which fields of an object should be discriminants, similar to readonly.
That way TS could indicate if you've accidentally broken the contract during refactoring - maybe it's overkill though.
Hope that answers your question, and thanks for raising it - I'll be more careful when creating object unions in the future. :)
* It wouldn't surprise me if there were some extra undocumented ways to narrow object unions!
Ah amazing! Your playground explains it really well. I guess my issue wasn't really related to your article 😅 - I hadn't realized that unions can only discriminate on literal types. Amazing that baz can be narrowed by foo - powerful stuff!
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Great article, thanks for writing it! I had a quick question:
I'm not sure I understand this point. What do type predicates on
foo
do to the inferred type ofbar
in these cases?Here's a playground of what I thought was supposed to happen but didn't
Thanks! :)
I definitely under explained this point... currently no type predicates on
foo
can act on the inferred type ofbar
.In your example,
bar
will always benumber | boolean
, regardless.However, type predicates on
foo
can influence the inferred type ofbaz
, provided it's available in scope. Hence the differentiation between destructuring in the function signature rather than in the body: in the former there's nobaz
to influence.I'm glad you raised this point because I realised I didn't know exactly how type narrowing works for object unions!
Your playground is a good example - I'd intuitively assume that the type of
foo
orbar
could be used to differentiate which part of the unionbaz
happens to be.That actually doesn't work, which surprised me.
If you ignore type predicate/guard functions, it turns out TS has just two ways* to narrow unions of objects: in operator narrowing and discriminated unions.
So you either have to add an extra property to one of the unions, e.g.
which defeats the point of destructuring, or by changing one of the fields to be a discriminant.
Discriminants must be a common property of the union where each type is a literal.
Here's a version of your playground where
foo
is now a discriminant, andbaz
is now influenced by a condition onfoo
.There's three types of literal types: strings, numbers and booleans.
I wonder if it'd be useful if there was a prefix keyword to indicate which fields of an object should be discriminants, similar to
readonly
.That way TS could indicate if you've accidentally broken the contract during refactoring - maybe it's overkill though.
Hope that answers your question, and thanks for raising it - I'll be more careful when creating object unions in the future. :)
* It wouldn't surprise me if there were some extra undocumented ways to narrow object unions!
Ah amazing! Your playground explains it really well. I guess my issue wasn't really related to your article 😅 - I hadn't realized that unions can only discriminate on literal types. Amazing that
baz
can be narrowed byfoo
- powerful stuff!