Search code examples
typescript

Is there a way to change type while maintaining the optional state of the type?


I would like to change the data of some fields to a customized type.

For example, I would like to change the b field of TSomeType to a custom type to get TSomeTypeConverted type as a result.

// original type
type TSomeType = {
    a: boolean;
    b: string;
}
// result what I want
type TSomeTypeConverted = {
    a: boolean;
    b: TCustomType;
}

Similar results were obtained by applying the TConvertToCustomType below.

type TConvertToCustomType<T, K extends keyof T> = Omit<T, K> & {[P in K]: TCustomType};

type TSomeTypeConverted = TConvertToCustomType<TSomeType, 'b'>
/* type TSomeTypeConverted = {
    a: boolean;
    b: TCustomType;
} */

However, in the process, all optional values are changed to required.

// before
type TSomeType = {
    a: boolean;
    b: string;
    c?: string; // optional
}
type TSomeTypeConverted = TConvertToCustomType<TSomeType, 'b' | 'c'>
/* type TSomeTypeConverted = {
    a: boolean;
    b: TCustomType;
    c: TCustomType; // not optional anymore
} */

Is there a way to change only the type while maintaining the optional status?


Solution

  • You can use Mapped Types with Conditional Type, instead of Omit & object:

    type TConvertToCustomType<T, K extends keyof T> = { [P in keyof T]: P extends K ? TCustomType : T[P] };
    
    type TSomeTypeConverted = TConvertToCustomType<TSomeType, 'b' | 'c'>
    /* type TSomeTypeConverted = {
        a: boolean;
        b: TCustomType;
        c?: TCustomType; // preserves optional flag
    } */
    

    Playground Link