Home > Net >  Typescript creating a utility type for converting multiple optional props into required props
Typescript creating a utility type for converting multiple optional props into required props

Time:03-28

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; }

TypeScript Playground Link

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; }

TypeScript Playground Link

  • Related