I am in the process of creating a utility type that could convert multiple explicitly specified optional props into required props.
I am able to convert single optional prop into a required prop using a custom utility as follows
type With<T, K extends keyof T> = T & { [P in K]-?: T[P] }
And then using in in the code as follows
type With<T, K extends keyof T> = T & { [P in K]-?: T[P] }
interface foo {
a?: 1
b?: 2
c?: 3
}
type fooWithA = With<foo, 'a'>
// equates into type: foo & {a:1}
So that works well.
But I can not wrap my head around how one would convert multiple props at once. I am not super familiar with type mapping, and I feel like researching is sadly not doing me any favors.
This is the (non-working) utility-type for multiple prop mapping that I have managed to assemble as of now:
type WithMultiple<T, K extends (keyof T)[]> = T & {
[P in keyof K]-?: K[P] extends keyof T ? T[K[P]] : never
}
// not working how I would want it to
Currently it acts as follows:
type WithMultiple<T, K extends (keyof T)[]> = T & {
[P in keyof K]-?: K[P] extends keyof T ? T[K[P]] : never
}
interface foo {
a?: 1
b?: 2
c?: 3
}
type fooWithAandB = WithMultiple<foo, ['a', 'b']>
// the type currently equates into: foo & [1 | undefined, 2 | undefined]
// even though I would need it to equate into something like: foo & {a:1, b:2}
What could point me in the right direction? I have been searching the web without real progress.
CodePudding user response:
Just use your original type and pass in the array's items as a union by indexing with number
:
type With<T, K extends keyof T> = T & { [P in K]-?: T[P] }
interface foo {
a?: 1
b?: 2
c?: 3
}
type fooWithA = With<foo, 'a'>;
type WithMultiple<T, K extends (keyof T)[]> = With<T, K[number]>;
type fooWithAB = WithMultiple<foo, ["a", "b"]>; // foo & { a: 1; b: 2; }
The array can be replaced with a string literal key union, however:
type With<T, K extends keyof T> = T & { [P in K]-?: T[P] }
interface Foo {
a?: 1
b?: 2
c?: 3
}
type FooWithA = With<Foo, 'a'>; // Foo & { a: 1; }
type FooWithAB = With<Foo, 'a' | 'b'>; // Foo & { a: 1; b: 2; }