I currently have these types in my .d.ts
.
type TransactionRowTypes = {
// transaction row types
}
type UserDataTypes = {
// user data types
}
type InventoryRowTypes = {
// inventory row types
}
type EventClientEvent = {
event: 'transactions' | 'userchange' | 'inventory';
time: number;
payload: Array<any>;
};
I want to make it so that, for example, when my EventClientEvent.event
is transactions
, I want the payload
to have a type of TransactionRowTypes
. If EventClientEvent.event
is userchange
, I want my payload
to have the type of UserDataTypes
, and so on. I’m having issues with trying to wrap my head around using conditional typing on its own object type, or if whether I am using this correctly. I have this type extractor, but I’m not sure on how to use it.
type EventName<T extends {event: string}> = T["event"];
Can anyone point me in the right direction? Thanks
4
Conditional types don’t really help with this. It looks like you want EventClientEvent
to be a discriminated union of the following form:
type EventClientEvent = {
event: "transactions";
time: number;
payload: TransactionRowTypes[];
} | {
event: "userchange";
time: number;
payload: UserDataTypes[];
} | {
event: "inventory";
time: number;
payload: InventoryRowTypes[];
}
You could define that manually, but if you want to be able to add/change event
/payload
pairings, you can instead write a mapping interface like
interface EventMapping {
transactions: TransactionRowTypes;
userchange: UserDataTypes;
inventory: InventoryRowTypes
}
and then use that to compute EventClientEvent
, like this:
type EventClientEvent = { [K in keyof EventMapping]:
{
event: K;
time: number;
payload: Array<EventMapping[K]>
}
}[keyof EventMapping]
That’s a distributive object type as coined in microsoft/TypeScript#47109 where we make a mapped type and then immediately index into it with the keys of that mapped type. It distributes the inner type {event: K; time: number; payload: Array<EventMapping[K]>}
over unions in K
, which in this case is keyof EventMapping
or "transactions" | "userchange" | "inventory"
.
You can verify that this evaluates to the equivalent type above.
Playground link to code.