I have a data structure that is deeply nested and I want to be able to reference an inner type in it, but that type doesn't have its own name/definition. For example:
MyQuery['system']['errors']['list'][number]
I auto-generate the MyQuery
type from a graphql query using graphql-codegen. I want the type of a single error
, but there are two problems:
- All those values in the middle are nullable
- I don't have an unique name for the error in my auto-generated types
I tried the following:
- works, but it is really hard to read:
type Error = NonNullable<NonNullable<NonNullable<MyQuery>['system']>['errors']>['list'][number]
- Doesn't work (
?.['field']
also doesn't work)
type Error = MyQuery?['system']?['errors']?['list']?[number]
- Works but creates unnecessary variable:
const error = queryResult?.system?.errors?.list?.[0]
type Error: typeof error
- Kinda works, but fields inside Error also become not null which I don't want
import { DeepNonNullable } from 'utility-types'
type Error = DeepNonNullable<MyQuery>['system']['errors']['list'][number]
Basically what I am asking is if there is an easier way to do "optional chaining for types" in typescript. My API is very null-prone and it would be very useful if I could do this more easily than using several NonNullable<T>
No, unfortunately, as of yet there is no native way to "optionally chain" deeply nested types. There is, however, quite a roundabout way of emulating that with a complex recursive conditional generic type and paths. First, you would need a reusable helper for handling index signatures:
Then you can create a helper type for recursively traversing the nested type relying on
infer
and template literal types to process the path:It's not pretty, but it allows for elegantly lensing into nested types: