Lets say I have the following interfaces:
interface IPargraph {
id: number,
value: string
}
interface ITask {
id: number,
date: Date
}
and the following union type:
export type BodyTypes = "PARAGRAPH" | "TASK" | "IMAGE"
how would I make it so the data property in the following interface will be either ITask
or IParagraph
based on the value of type
export interface INoteBody {
type: BodyTypes
data: **ITask or IParagraph based on which BodyTypes is used**
}
For example, this shouldn't be valid:
const note: INoteBody = {
type: "PARAGRAPH",
data: {
id: 1,
date: new Date()
}
}
CodePudding user response:
Try this:
interface IPargraph {
id: number
value: string
}
interface ITask {
id: number
date: Date
}
export type BodyMap = {
"PARAGRAPH": IPargraph
"TASK": ITask
"IMAGE": any
}
type BodyType = keyof BodyMap
export interface INoteBody<T extends BodyType> {
type: T
data: BodyMap[T]
}
const date: INoteBody<"TASK"> = {
type: "TASK",
data: {
id: 2,
date: new Date(),
},
}
const paragraph: INoteBody<"PARAGRAPH"> = {
type: "PARAGRAPH",
data: {
id: 1,
value: 'any value',
},
}
It is also possible to change from interface
to type
, to avoid the explicit Generic:
type INoteGeneric<T> = T extends keyof BodyMap ? {
type: T;
data: BodyMap[T];
} : never;
type INote = INoteGeneric<keyof BodyMap>;
const dateWithType: INote = {
type: "TASK",
data: {
id: 2,
date: new Date(),
},
}
const paragraphWithType: INote = {
type: "PARAGRAPH",
data: {
id: 1,
value: 'any value',
},
}