如何从可能为undefined的嵌套TypeScript类型中提取内部属性类型
我有一段由graphql codegen自动生成的TypeScript类型(无法手动修改,会随GraphQL查询更新):
type User = { user?: { subscription?: {...} | null | undefined, ... } | null | undefined };
我想提取subscription的类型,于是写了这段代码:
type SubscriptionType = User['user']['subscription'];
但TypeScript抛出了错误:
typescript: Property 'subscription' does not exist on type '{ __typename?: "users" | undefined; subscription?: { __typename?: "subscriptions" | undefined; id: number; activeSince?: any; renewalDate?: any; endingDate?: any; ... 7 more ...; } | null | undefined; } | null | undefined'.
同时SubscriptionType被推断成了any类型。
问题出在User['user']的类型是对象 | null | undefined,直接访问subscription时TypeScript无法确定它是否存在于所有可能的分支上。以下是几种安全提取类型的方法:
方法1:逐层条件类型提取
通过条件类型逐层拆解结构,自动处理空值分支:
type GetSubscription<T> = T extends { user?: infer U } ? U extends { subscription?: infer S } ? S : never : never; type SubscriptionType = GetSubscription<User>;
这个类型会先从User里提取user的类型,再从user的类型里提取subscription的类型,不管中间层有没有null或undefined都能正确处理。
方法2:筛选非空类型后访问
先用Extract把user的非空对象类型筛选出来,再访问subscription:
type NonNullableUser = Extract<User['user'], object>; type SubscriptionType = NonNullableUser['subscription'];
Extract<User['user'], object>会排除null和undefined,只保留user的对象类型,之后就能安全访问subscription了。
方法3:链式使用NonNullable
如果使用TypeScript 4.5及以上版本,可以用NonNullable链式处理空值:
// 得到subscription的非空类型 type SubscriptionType = NonNullable<NonNullable<User['user']>['subscription']>; // 如果要保留subscription本身的null/undefined可能性 type SubscriptionType = NonNullable<User['user']>['subscription'];
内层NonNullable处理user的空值,外层处理subscription的空值,按需选择是否保留subscription的空值类型。
内容的提问来源于stack exchange,提问作者Riptide

