简体   繁体   English

typescript 类型的可选链接

[英]Optional chaining for typescript types

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.我使用 graphql-codegen 从 graphql 查询自动生成MyQuery类型。 I want the type of a single error , but there are two problems:我想要单个error的类型,但是有两个问题:

  1. All those values in the middle are nullable中间的所有这些值都是可以为空的
  2. I don't have an unique name for the error in my auto-generated types我的自动生成类型中的错误没有唯一名称

I tried the following:我尝试了以下方法:

  1. works, but it is really hard to read:有效,但真的很难阅读:
type Error = NonNullable<NonNullable<NonNullable<MyQuery>['system']>['errors']>['list'][number]
  1. Doesn't work ( ?.['field'] also doesn't work)不起作用( ?.['field']也不起作用)
type Error = MyQuery?['system']?['errors']?['list']?[number]
  1. Works but creates unnecessary variable:有效但创建不必要的变量:
const error = queryResult?.system?.errors?.list?.[0]
type Error: typeof error
  1. Kinda works, but fields inside Error also become not null which I don't want有点工作,但错误中的字段也不是我不想要的 null
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.基本上我要问的是在 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>我的 API 非常容易出现空值,如果我可以比使用几个NonNullable<T>更容易地做到这一点,那将非常有用

if there is an easier way to do "optional chaining for types"如果有更简单的方法来做“类型的可选链接”

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:首先,您需要一个可重用的助手来处理索引签名:

type _IndexAccess<T, U extends keyof T, V extends string> = V extends "number" 
    ? Exclude<T[U], undefined> extends { [x:number]: any } ? 
        Exclude<T[U], undefined>[number]
        : undefined
    : V extends "string" ?
        Exclude<T[U], undefined> extends { [x:string]: any } ?
            Exclude<T[U], undefined>[string]
            : undefined
    : V extends "symbol" ?
        Exclude<T[U], undefined> extends { [x:symbol]: any } ?
            Exclude<T[U], undefined>[symbol]
            : undefined
    : undefined;

Then you can create a helper type for recursively traversing the nested type relying on infer and template literal types to process the path:然后,您可以创建一个辅助类型,用于递归遍历依赖于infer和模板文字类型的嵌套类型来处理路径:

type DeepAccess<T, K extends string> = K extends keyof T 
    ? T[K] 
    : K extends `${infer A}.${infer B}` 
        ? A extends keyof T 
            ? DeepAccess<Exclude<T[A], undefined>, B>
            : A extends `${infer C}[${infer D}]`
                ? DeepAccess<_IndexAccess<T, C extends keyof T ? C : never, D>, B>
                : undefined
    : K extends `${infer A}[${infer B}]` 
        ? A extends keyof T 
            ? B extends keyof T[A] 
                ? T[A][B] 
                : _IndexAccess<T, A, B>       
            : undefined
    : undefined;

It's not pretty, but it allows for elegantly lensing into nested types:它并不漂亮,但它允许优雅地映射到嵌套类型:

type MyQuery = {
    system?: {
        errors?: {
            list?: [{
                answer: 42,
                questions: { known: false }[]
            }]
        }
    }
};

// false
type t1 = DeepAccess<MyQuery, "system.errors.list[number].questions[number].known">;

// [{ answer: 42; questions: { known: false; }[]; }] | undefined
type t2 = DeepAccess<MyQuery, "system.errors.list">;

// 42
type t3 = DeepAccess<MyQuery, "system.errors.list[number].answer">;

// undefined
type t4 = DeepAccess<MyQuery, "system.errors.list.unknown">;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM