Reputation: 576
I have an interface as:
export interface PostEventTypeMap {
changePrice: number;
changeQuantity: number;
signalConnected: boolean;
signalDisconnected: boolean;
}
how I can define a type alias like:
type PostEvent = {
type: keyof PostEventTypeMap,
value: **Value based on key value and PostEventTypeMap**
};
I can not make postEvent property generic:
PostBoxService {
get postEvent(): Observable<PostEvent> {
return getOrCreateValue(this, "postEvent", () => new BehaviorSubject(null));
}
}
The usecase of service:
postBoxService
.postEvent
.subscribe(event => {
if (!event)
return;
switch (event.type) {
case "changePrice":
this.changePrice(event.value);
break;
case "changeQuantity":
this.changeQuantity(event.value);
break;
}
});
Upvotes: 1
Views: 1862
Reputation: 328142
Because you have a finite number of possibilities, and since the type
value will always be a literal type, you can make this a discriminated union. One way to do this is to map the PostEventTypeMap
properties to the union members you want, and then immediately look up these properties to get a union:
type ObjToTypeValueUnion<T extends object> =
{ [K in keyof T]-?: { type: K, value: T[K] } }[keyof T]
type PostEvent = ObjToTypeValueUnion<PostEventTypeMap>;
/* type PostEvent = {
type: "changePrice";
value: number;
} | {
type: "changeQuantity";
value: number;
} | {
type: "signalConnected";
value: boolean;
} | {
type: "signalDisconnected";
value: boolean;
} */
You can verify that this works as desired for your use case:
declare function changePrice(x: number): void;
declare function changeQuantity(x: number): void;
((event?: PostEvent) => {
if (!event)
return;
switch (event.type) {
case "changePrice":
changePrice(event.value);
break;
case "changeQuantity":
changeQuantity(event.value);
break;
}
});
Upvotes: 3
Reputation: 2724
You may need to make the PostEvent
type generic, as in:
export interface PostEventTypeMap {
changePrice: number;
changeQuantity: number;
signalConnected: boolean;
signalDisconnected: boolean;
}
type PostEvent<T extends keyof PostEventTypeMap> = {
type: T,
value: PostEventTypeMap[T]
};
const validChangePrice: PostEvent<'changePrice'> = {
type: 'changePrice',
value: 1
}
const invalidChangePrice: PostEvent<'changePrice'> = {
type: 'changePrice',
value: true // Compile error TS2322: Type 'true' is not assignable to type 'number'.
}
Upvotes: 1