Given the following interface described on this TS playground
export type GetTestimonialsSectionQuery = {
__typename?: 'Query',
testimonialsSection?: {
__typename?: 'TestimonialsSection',
id: string,
testimonials: Array<{ __typename?: 'Testimonial', id: string, text: string, author?: { __typename?: 'TestimonialAuthor', id: string, name: string, photo: { __typename?: 'Asset', url: string } } | null }>
} | null };
I would like to access the testimonials
index from the whole interface by using the indexed access type, however, it doesn't work when the strictNullChecks
compiler option is set and the result is any
Since testimonials
can be undefined
, would a type check needed before accessing the nested property?
CodePudding user response:
You can only perform an indexed access of the form T[K]
when K
is definitely a key type for K
; that is, when K extends keyof T
. If T
is a union type then the only definite keys of T
are those keys present on every member of the union. That is, keyof (A | B | C)
becomes (keyof A) & (keyof B) & (keyof C)
.
In your case, since GetTestimonialsSectionQuery['testimonialsSection']
is a union of an object type with both null
and undefined
, you won't be allowed to index into it with anything that isn't also a key of null
and undefined
... and null
and undefined
have no keys; you can't index into them at all. Hence the error:
type Bad = GetTestimonialsSectionQuery[
'testimonialsSection']['testimonials'] // error!
// ----------------------> ~~~~~~~~~~~~~~
// Property 'testimonials' does not exist on type ...
If all you care about is the object type and not the null
and undefined
, you can use a utility type to filter the union to just the object type before indexing into it. In general, you can filter unions via the Exclude<T, U>
utility type, but for the specific and common case of removing null
and undefined
, you can use the NonNullable<T>
utility type:
type Testimonials = NonNullable<
GetTestimonialsSectionQuery['testimonialsSection']
>['testimonials']
/* type Testimonials = {
__typename?: "Testimonial" | undefined;
id: string;
text: string;
author?: {
__typename?: "TestimonialAuthor" | undefined;
id: string;
name: string;
photo: {
__typename?: 'Asset';
url: string;
};
} | null | undefined;
}[] */
type Testimonials = NonNullable<
GetTestimonialsSectionQuery['testimonialsSection']
>['testimonials']
/* type Testimonials = {
__typename?: "Testimonial" | undefined;
id: string;
text: string;
author?: {
__typename?: "TestimonialAuthor" | undefined;
id: string;
name: string;
photo: {
__typename?: 'Asset';
url: string;
};
} | null | undefined;
}[] */
Looks good!