我有以下类型:
interface A {
p1: string
p2?: string
}
我想生成一个子类型B
,并将可选属性转换为可为空的属性。等同于:
interface B {
p1: string
p2: string | null
}
我尝试过这样的事情:
type VuexPick<T, K extends keyof T> = {
[P in K]-?: T[P] extends undefined ? null : T[P];
};
type B = VuexPick<A, "p1" | "p2">;
但是它不起作用。有想法吗?
答案 0 :(得分:1)
这有效:
export type OptionalTuNullable<O> = {
[K in keyof O]-?: undefined extends O[K] ? NonNullable<O[K]> | null : O[K];
};
例如:
type R = {
a: string;
b?: string;
c?: string | null;
d: string | undefined;
};
type A = OptionalTuNullable<R>;
// A: {
// a: string;
// b: string | null;
// c: string | null;
// d: string | null;
// }
然后,对于“ Pick”部分,您可以使用标准的Pick
类型:
type B = Pick<A, "a" | "c">;
// B: {
// a: string;
// c: string | null;
// }
总结一下,我认为这将适合您的用例:
type VuexPick<T, K extends keyof T> = Pick<OptionalTuNullable<T>, K>
type C = VuexPick<R, 'c'>
// C: {
// c: string | null;
// }
答案 1 :(得分:1)
您的类型B
可以解决此问题:
type B = {
p1: string extends undefined ? null : string
p2: string | undefined extends undefined ? null : string | undefined
};
string | undefined
,因为超类型不会扩展undefined
,反之亦然。因此,您最终得到以下类型:
type B = {
p1: string;
p2: string;
}
您可以改为创建UndefinedToNull
类型,这会导致应用distributive conditional type,因为T
现在是naked type parameter。
type VuexPick2<T, K extends keyof T> = {
[P in K]-?: UndefinedToNull<T[P]>;
};
type UndefinedToNull<T> = T extends undefined ? null : T
type B2 = VuexPick2<A, "p1" | "p2">; // type B2 = { p1: string; p2: string | null;}
例如类型UndefinedToNull<string | undefined>
与B4
相同:
type B4 =
| (string extends undefined ? null: string)
| (undefined extends undefined ? null: undefined) // type B4 = string | null