Typescript: overwrite Record value type in another type

Imagine I have the following interface defined:

export interface BaseInterface {
    foo?: Record<string, SomeType>;
    bar?: Record<string, SomeOtherType>;
    ... // Many more fields like this
}

I want to create a new type, which will be equivalent to BaseInterface, except all record types should be wrapped in Partial like this:

export type MyType = {
    foo?: Record<string, Partial<SomeType>>;
    bar?: Record<string, Partial<SomeOtherType>>;
    ...
}

I don’t want to manually write the new interface, because there are too many fields in the base interface + there are multiple interfaces that I need to overwrite like this, so I would like to find out if there is a way to achieve the same result using some TypeScript magic.

>Solution :

You can use a conditional type to extract the record value type and make that partial. We can then use a mapped type to apply to all properties:

type RecordValuePartial<T> = T extends Record<string, infer V>? Record<string, Partial<V>>: T
type AllRecordValuePartial<T> = {
  [P in keyof T]: RecordValuePartial<T[P]>
}


export type MyType = AllRecordValuePartial<BaseInterface> // Same as: 
// export type MyTypeManual = {
//     foo?: Record<string, Partial<SomeType>> | undefined;
//     bar?: Record<string, Partial<SomeOtherType>>| undefined ;
    
// }

Playground Link

Leave a Reply