递归应用一个复杂的泛型类型

4

感谢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>[] }

这是可能的吗?


哇,我刚刚提到了递归类型定义(尽管在不同的上下文中),这实际上让我想知道是否有可能有任何类型的递归类型。然后这个问题就出现了。值得一提的是,理论上似乎应该是可能的,至少是可以实现的。不确定是否已经被实现。 - VLAZ
1个回答

2
更新:包括 TS 3.7 版本和数组类型。
你的意思是这样吗?
TS 3.7+(数组中的通用类型参数现在可以是循环):
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>> {}

游乐场

测试类型:
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)

1
感谢您更新数组。非常有趣。 - Paleo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接