递归地应用复杂的泛型类型

2023-12-24

谢谢一个答案 https://stackoverflow.com/questions/58409603/generate-a-type-where-each-nullable-value-becomes-optional来自 Nit,我有一个通用类型NullValuesToOptional生成每个可为空值变为可选的类型:

type NullValuesToOptional<T> = Omit<T, NullableKeys<T>> & Partial<Pick<T, NullableKeys<T>>>;

type NullableKeys<T> = NonNullable<({
  [K in keyof T]: T[K] extends NonNull<T[K]> ? never : K
})[keyof T]>;

type NonNull<T> = T extends null ? never : T;

有用:

interface A {
  a: string
  b: string | null
}
type B = NullValuesToOptional<A>; // { a: string, b?: string | null }

现在我想做NullValuesToOptional递归:

interface C {
  c: string
  d: A | null
  e: A[]
}
type D = NullValuesToOptional<C>;
// { c: string, d?: NullValuesToOptional<A> | null, e: NullValuesToOptional<A>[] }

是否可以?


更新:包含 TS 3.7 版本 + 数组类型


你的意思是这样的吗?

TS 3.7+(数组中的通用类型参数现在可以是circular https://github.com/microsoft/TypeScript/pull/33050):

type RecNullValuesToOptional<T> = T extends Array<any>
  ? Array<RecNullValuesToOptional<T[number]>>
  : T extends object
  ? NullValuesToOptional<{ [K in keyof T]: RecNullValuesToOptional<T[K]> }>
  : T;

界面是必要的):

type RecNullValuesToOptional<T> = T extends Array<any>
  ? RecNullValuesToOptionalArray<T[number]>
  : T extends object
  ? NullValuesToOptional<{ [K in keyof T]: RecNullValuesToOptional<T[K]> }>
  : T;

interface RecNullValuesToOptionalArray<T>
  extends Array<RecNullValuesToOptional<T>> {}

操场 https://www.typescriptlang.org/play/#code/C4TwDgpgBAcgrgGwQNQIYLhAzgFQPYDyYwAlngHboA8OAfFALxQEC2JwNANLIgqgEYIIAaQggsNWvQBkAKChQACqgBOpaopIBjANZceSAUNHjJUgNyzZoSAb6CRYiXUawK8Qw6ryoACgDeUADawlAk5FA6YngAZlA4ALoAXPEhCVAQAB7AEOQAJlhu5B4INGn0APxQ5BAAbhAqUCmhAL4AlEFRILHxCbK0ltbg0DDuvJKuOBnZuQXVvFBVNfWNKTiD4TkqMaha0ACCUP4+qClYwCrhAOaWCvxnF9dQAD7zSJYtQ7YAQq4laBhsPgiKQKNR9gMoAB6KFHKCnKDnS7kK7cfgVB7Iq4vN4IKCfWSbBo7PZQADCRx8Wkx11uUDyKUOr3IvDpEEZQQSdJiKRZLH4DU5OJZ71kBJs0AAIn9eADMLhCMQyJRSmSBlYJVAAEoQLT-dDy4FKsGlFxMKZZHL5Qr7FQqVAgKiocggWg+Ko6vWyg1AxWglW2+2OnBBPkClQJN0KNbTK1zPD8ABWuuA7rsct9IOV1ECITCES6PUSKU9+sBCqzJrKwkj+KjTXidMJ5C2JOgpe95aN-vQgYdkh8ltmNrt-Y7SAzFeNKrMR3FwygAFFXOOUD6pz3VerZDCoMAABYkQpHqCJuDnKAxPCNEhIc8XVD+qBgOAqMB4LDQYB4KAC4BbRF9zwAB3Pd9y-BdwjA6AAElJUXL5oAAMT4f9cgmc1Y2HKAE2TLRUwUKoLRma18xiBpmB8Qi4TzKDCziAhkigFDHytKgCHKfEqIbZYGh8NZLE1RckOvFhWIgPJXBYtDyCoRdty0CgL3ZJdXGOBRqSgAAiK88C0zgfAZOEES0-hVH038UlM1AAC8tPxAyFBUoJAhMsyVAs+5tIARzgTJ7JabhXKs3y-ICvoWksRTyGUgAmFJlyYdSoE0nS8D0xz6RSYLtPczyrLMuyHMHFIXMsnywoc4yQrgSqWgi8xoVhBoVGvbhUCgNgsCwa5ZCAA

测试类型:

interface A {
  a: string;
  b: string | null;
}

interface C {
  c: string;
  d: A | null;
  e: A[];
  f: number[] | null;
}

/*
type EFormatted  = {
    c: string;
    e: {
        a: string;
        b?: string | null | undefined;
    }[];
    d?: {
        a: string;
        b?: string | null | undefined;
    } | null | undefined;
    f?: number[] | null | undefined;
}

=> type EFormatted is the "flattened" version of 
type E and used for illustration purposes here;
both types E and EFormatted are equivalent, see also Playground
*/
type E = RecNullValuesToOptional<C>

用一些数据进行测试:

const e: E = {
  c: "foo",
  d: { a: "bar", b: "baz" },
  e: [{ a: "bar", b: "qux" }, { a: "quux" }]
};
const e2: E = {
  c: "foo",
  d: { a: "bar", b: "baz" },
  e: [{ b: "qux" }, { a: "quux" }]
}; // error, a missing (jep, that's OK)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

递归地应用复杂的泛型类型 的相关文章

随机推荐