Home > Mobile >  How to create a type from another type that has a specific property with diffente type in TypeScript
How to create a type from another type that has a specific property with diffente type in TypeScript

Time:12-05

I have this type:

type Period = 'Monthly' | 'Yearly'
type Cycle = {
    period: Period,
    price: number
}

And I want to get the following type (basically, allow period to be an empty string):

type Period = 'Monthly' | 'Yearly'
type EditableCycle = {
    period: Period | '',
    price: number
}

I was thinking about something like this made up syntax:

type EditableCycle = Extend<Cycle, { period: '' }>

How can I achieve it?

The reason, I want the user to be able to don't choose any period when editing (hende period can be an empty string) but after validating it I'm sure period will hold a valid Period.

note: the real type is much more complicated than Cycle, involving arrays and similar stuff, this is a cut down example.

CodePudding user response:

You can use the Omit utility type to override the period field:

type Period = 'Monthly' | 'Yearly'
type Cycle = {
    period: Period,
    price: number
}

type EditableCycle = Omit<Cycle, "period"> & {
  period: Period | ''
}

const editableCycle: EditableCycle = {
  period: '',
  price: 5
}

If this solution works for you, you can go one step further and create your own Override type like this:

type Period = 'Monthly' | 'Yearly'
type Cycle = {
    period: Period,
    price: number
}

type Override<T, K> = Omit<T, keyof K> & K

type EditableCycle = Override<Cycle, {
  period: Period | ''
}>

const editableCycle: EditableCycle = {
  period: '',
  price: 5
}

I hope you find this answer helpful.

François

CodePudding user response:

Here's how to type the Extend utility in your question (I've renamed it to UnifyProps because it produces a new type including all properties in both parameters, creating a union of the types of parameters with shared names):

TS Playground link

type UnifyProps<T1, T2> = {
  [K in keyof T1]: K extends keyof T2 ? (T1[K] | T2[K]) : T1[K];
} & {
  [K in keyof T2]: K extends keyof T1 ? (T1[K] | T2[K]) : T2[K];
};

type Period = 'Monthly' | 'Yearly';

type Cycle = {
  period: Period;
  price: number;
};

type EditableCycle = UnifyProps<Cycle, { period: '' }>;

declare const ec: EditableCycle;
ec.period = 'Monthly'; // ok
ec.period = 'Yearly'; // ok
ec.period = ''; // ok
ec.period = 'another string'; /*
^^^^^^^^^
Type '"another string"' is not assignable to type '"" | Period'. (2322) */
  • Related