0

我使用 Graphql codegen 从我们的模式生成类型。我需要访问嵌套类型并常用以下方法:

 type Iresponse = myType[level1][level2]

当没有 Maybes 时,这很有效,这意味着它有可能为空。当类型被定义为“可能”时,我无法使用它并且它会引发错误。

有没有人有一个实用的解决方案来指定这些嵌套类型?我不想将每一步都包装在许多非可空泛型中......

先感谢您 !

4

3 回答 3

2

任意深度:

type Get<T, X> = X extends keyof T ? T[X] : never
type Path<T, P extends any[]> = P extends [infer X, ...infer Y] ? Path<Get<NonNullable<T>, X>, Y> : T

type Iresponse = Path<myType, ["level1", "level2", "response"]>

游乐场链接

于 2021-09-13T15:14:48.140 回答
2

您可以使用内置的NonNullable util

type MyType = {
    foo: {
        bar: [1, 2, 4] | null
    } | null
}


type GetNullable<T, Prop extends keyof NonNullable<T>> = NonNullable<T>[Prop]

// [1, 2, 4] | null
type NestedData = GetNullable<MyType['foo'], 'bar'>


操场

或者

type Truthy<T> = NonNullable<T>

type GetData = Truthy<Truthy<MyType['foo']>>['bar']

如果您需要更复杂的实用程序,请参阅此示例最后一行和相关答案

type Structure = {
    user: {
        tuple: [42],
        emptyTuple: [],
        array: { age: number }[]|null
    }
}

type Values<T> = T[keyof T]

type IsNever<T> = [T] extends [never] ? true : false;

type IsTuple<T> =
    (T extends Array<any> ?
        (T['length'] extends number
            ? (number extends T['length']
                ? false
                : true)
            : true)
        : false)

type IsEmptyTuple<T extends Array<any>> = T['length'] extends 0 ? true : false

type HandleDot<
    Cache extends string,
    Prop extends string | number
    > =
    Cache extends ''
    ? `${Prop}`
    : `${Cache}.${Prop}`

type HandleObject<Obj, Cache extends string> = {
    [Prop in keyof Obj]:
    | HandleDot<Cache, Prop & string>
    | Path<Obj[Prop], HandleDot<Cache, Prop & string>>
}[keyof Obj]

type Path<Obj, Cache extends string = ''> =
    (Obj extends PropertyKey
        ? Cache
        : (Obj extends Array<unknown>
            ? (IsTuple<Obj> extends true
                ? (IsEmptyTuple<Obj> extends true
                    ? Path<PropertyKey, HandleDot<Cache, -1>>
                    : HandleObject<Obj, Cache>)
                : Path<Obj[number], HandleDot<Cache, number>>)
            : HandleObject<Obj, Cache>)
    )

type WithDot<T extends string> = T extends `${string}.${string}` ? T : never


type Acc = Record<string, any>

type ReducerCallback<Accumulator extends Acc, El extends string> =
    El extends keyof Accumulator ? Accumulator[El] : El extends '-1' ? never : Accumulator

type Reducer<
    Keys extends string,
    Accumulator extends Acc = {}
    > =
    Keys extends `${infer Prop}.${infer Rest}`
    ? Reducer<Rest, ReducerCallback<Accumulator, Prop>>
    : Keys extends `${infer Last}`
    ? ReducerCallback<Accumulator, Last>
    : never


type BlackMagic<T> = T & {
    [Prop in WithDot<Extract<Path<Structure>, string>>]: Reducer<Prop, T>
}

type Result = Reducer<'user.array', Structure>

操场

于 2021-09-13T15:09:18.157 回答
0

谢谢你们的回答,他们真的很有帮助!

我最终做的是在 graphql 生成器中使用“typescript-compatibility”。它添加了也可能为 null 的类型和子类型。基本上它所做的只是将所有嵌套类型包装在 NonNullable 类型中。

于 2021-09-17T06:25:06.180 回答