Required<T> does not work for secondary lookup types

If I have some code like:
type Bravo = {
b?: string;
}
type Charlie = {
c:Bravo['b']
}
function acceptsCharlie(value: Charlie){
//'value.c' is possibly 'undefined'.(18048)
value.c.split('');
}
This makes sense - the type Charlie
inherits the optional string from Bravo
.
We can solve this by using the Required
utility type:
type Bravo = {
b?: string;
}
type Charlie = {
// 👇
c:Required<Bravo>['b']
}
function acceptsCharlie(value: Charlie){
// no error here
value.c.split('');
}
Easy.
However, if I add one more layer of typing look-up-ing:
type Alpha = {
a?: string;
}
type Bravo = {
b: Alpha['a'];
}
type Charlie = {
c: Required<Bravo>['b']
}
function acceptsCharlie(value: Charlie){
//'value.c' is possibly 'undefined'.(18048)
value.c.split('');
}
The Required
no longer solves the problem for me.
What gives?
Answer
The difference between ?
and | undefined
is that in the first situation the field can be skipped, while in the second field needs to exist, even if it can have undefined
as a value.
Required
works on only optional fields.
If a field is typed as field : X | undefined
, then Required will have no effect on it.
Whereas when it is typed as field? : X
, then Required
works:
What you are doing with the indirection is that now Bravo
definitely has the field b
, it might be undefined or string, but it is not optional. So in that case Required can not do much.
Excerpt from the release notes of TS 2.8:
Using this ability, lib.d.ts now has a new Required type. This type strips ? modifiers from all properties of T, thus making all properties required.
Enjoyed this article?
Check out more content on our blog or follow us on social media.
Browse more articles