Reputation: 3321
interface Tenant {
id: number;
name: string;
}
interface Server {
id: number;
location: string;
ip: string;
}
interface User {
id: number;
name: string;
tenant: number | Tenant;
server: number | Server;
}
Properties tenant
and server
could be "populated" but by default, they are not. I want to be able to define the type and specify which properties are populated, like this:
const user: User; // both tenant and server are number
const user2: User<{ tenant: Tenant }>; // tenant is populated, server - not
const user3: User<{ tenant: Tenant; server: Server }>; // both props are populated
interface UserPopulate {
tenant: Tenant | number;
server: Server | number;
}
interface DefaultUserPopulate {
tenant: number;
server: number;
}
export interface User2<Populate extends UserPopulate = DefaultUserPopulate>{
id: number;
name: string;
tenant: Populate['tenant'];
server: Populate['server'];
}
const user: User<{ tenant: number }>;
But Typescript requires me to define both tenant
and server
(User<{ tenant: number; server: number }>
or nothing (User
), but I want to be able to override only one "populate"
Upvotes: 0
Views: 1305
Reputation: 707
The answer is conditional types:
interface User<T = {}> {
id: number;
name: string;
tenant: T extends {tenant: Tenant} ? Tenant : number;
server: T extends {server: Server} ? Server : number;
}
But a better approach would be to simplify T
as the object type is not carrying any useful information, so a simple string union would do.
interface User<T extends "tenant" | "server" | "default" = "default"> {
id: number;
name: string;
tenant: "tenant" extends T ? Tenant : number;
server: "server" extends T ? Server : number;
}
let user: User; // both tenant and server are number
let user2: User<"tenant">; // tenant is populated, server - not
let user3: User<"tenant" | "server">; // both props are populated
Upvotes: 2