Вообще-то, на мой взгляд самый нормальный способ - такой: песочница
enum UserRole {
Trainer = 'Тренер',
Client = 'Клиент',
}
export interface ITrainer {
userRole: UserRole.Trainer;
certificate: string;
merits: string;
personalTraining: boolean;
}
export interface IClient {
userRole: UserRole.Client;
caloriesToLose: number;
readyToTraining: boolean;
}
type User = ITrainer | IClient;
Если всё же по какой-то причине не хочется добавлять userRole
в эти интерфейсы, то можно намутить такое: песочница
enum UserRole {
Trainer = 'Тренер',
Client = 'Клиент',
}
type User =
| { userRole: UserRole.Trainer } & ITrainer
| { userRole: UserRole.Client } & IClient
export interface ITrainer {
certificate: string;
merits: string;
personalTraining: boolean;
}
export interface IClient {
caloriesToLose: number;
readyToTraining: boolean;
}
Если типов больше, то можно немного упростить (заодно тайпскрипт проконтролирует, что перечислены все роли): песочница
enum UserRole {
Trainer = 'Тренер',
Client = 'Клиент',
}
type User = {
[role in UserRole]: { userRole: role } & {
[UserRole.Trainer]: ITrainer,
[UserRole.Client]: IClient,
}[role]
}[UserRole]
export interface ITrainer {
certificate: string;
merits: string;
personalTraining: boolean;
}
export interface IClient {
caloriesToLose: number;
readyToTraining: boolean;
}
Сюда же можно прикрутить общие поля из любого типа: песочница
enum UserRole {
Trainer = 'Тренер',
Client = 'Клиент',
}
type BaseUser = {
userRole: UserRole;
login: string;
passwordHash: string;
}
type IUser = Omit<BaseUser, "passwordHash"> & {
password: string;
}
type User = {
[role in UserRole]: { userRole: role } & IUser & {
[UserRole.Trainer]: ITrainer,
[UserRole.Client]: IClient,
}[role]
}[UserRole]
export interface ITrainer {
certificate: string;
merits: string;
personalTraining: boolean;
}
export interface IClient {
caloriesToLose: number;
readyToTraining: boolean;
}