Search code examples
typescripttypescript-typestypescript-utility

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