Reputation: 23772
I have the following type:
interface A {
p1: string
p2?: string
}
I would like to generate a sub-type B
with optional properties converted to nullable properties. Something equivalent to:
interface B {
p1: string
p2: string | null
}
I tried something like this:
type VuexPick<T, K extends keyof T> = {
[P in K]-?: T[P] extends undefined ? null : T[P];
};
type B = VuexPick<A, "p1" | "p2">;
But it doesn't work. Any idea?
Upvotes: 3
Views: 3214
Reputation: 74820
Your type B
gets resolved to this:
type B = {
p1: string extends undefined ? null : string
p2: string | undefined extends undefined ? null : string | undefined
};
string | undefined
as supertype does not extend undefined
, it is the other way around. So you end up with this type:
type B = {
p1: string;
p2: string;
}
You could instead create a UndefinedToNull
type, which causes a distributive conditional type to be applied, as T
is a naked type parameter now.
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;}
E.g. type UndefinedToNull<string | undefined>
is the same as B4
:
type B4 =
| (string extends undefined ? null: string)
| (undefined extends undefined ? null: undefined) // type B4 = string | null
Upvotes: 3
Reputation: 1315
This works:
export type OptionalTuNullable<O> = {
[K in keyof O]-?: undefined extends O[K] ? NonNullable<O[K]> | null : O[K];
};
So for instance:
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;
// }
Then, for the "Pick" part, you can just resort to the standard Pick
type:
type B = Pick<A, "a" | "c">;
// B: {
// a: string;
// c: string | null;
// }
Summing up, I think this would work for your use case:
type VuexPick<T, K extends keyof T> = Pick<OptionalTuNullable<T>, K>
type C = VuexPick<R, 'c'>
// C: {
// c: string | null;
// }
Upvotes: 4