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"
};