Home > Blockchain >  Typescript: Define if property should be included based on value of other property
Typescript: Define if property should be included based on value of other property

Time:06-22

I'm using Typescript with React and struggling to get a type correct.. What I am trying to achieve is that for the interface Car the property colorId is required if carColor is 'blue' otherwise it should not be included. Any feedback on how to achieve this?

interface Car {
    carBrand: string;
    carColor: 'black' | 'blue';
    colorId?: string;
}

CodePudding user response:

You can use generics and Omit.

Create a BaseCar interface that has carBrand, carColor and carId properties and then create a Car type that conditionally decides the colorId property.

interface BaseCar {
  carBrand: string;
  carColor: "black" | "blue";
  colorId: string;
}

type Car<T extends "black" | "blue"> = T extends "black"
  ? Omit<BaseCar, "colorId">
  : BaseCar;

const blueCar: Car<"blue"> = {
  carBrand: "tesla",
  carColor: "blue",
  colorId: "123",
};

const blackCar: Car<"black"> = {
  carBrand: "honda",
  carColor: "black",
};

// @ts-expect-error
const blueCarWithoutId: Car<"blue"> = {
  carBrand: "tesla",
  carColor: "blue",
};

const blackCarWithId: Car<"black"> = {
  carBrand: "honda",
  carColor: "black",
  // @ts-expect-error
  colorId: "123"
};

CodePudding user response:

type CarColors = "black" | "blue";

// create generic that passed color as asgument
interface Car<C extends CarColors = "black"> {
  carBrand: string;
  carColor: C;
  colorId: string;
}

// create conditional type that omits carColor when color is black
type ColoredCar<C extends CarColors = "black"> = C extends "blue" ? Car<"blue"> : Omit<Car, "carColor">;

// use agrument blue to require color
const myCar: ColoredCar<"blue"> = {
  carBrand: "bmw",
  carColor: "blue",
  colorId: "123"
};

// otherwise it is omitted 
const myCar2: ColoredCar = {
  carBrand: "bmw",
  colorId: "123"
};
  • Related