Last active
May 23, 2022 23:37
-
-
Save polerin/28b598e9f097dde63df57b8e90160dc3 to your computer and use it in GitHub Desktop.
Typescript Type mapping / const / etc issues
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import MessageBridge from "./MessageBridge"; | |
import { AppMessageMap, AppMessageNames as messageNames } from "./MessageMap"; | |
const bridge = new MessageBridge<AppMessageMap>(); | |
// Desired functionality is something like this? | |
// * easily accessible const/symbol/something defining the message name (no magic string) | |
// * easily accessible type definition for the message (don't have to go around the world to look it up) | |
bridge.subscribe(messageNames.TwitchRaid, (AppMessageMap[TwitchRaid]) => { /* ... */ }); | |
// * nice to have: an empty message factory, but that's not a requirement and I know it might be harder? | |
const raidMessage : AppMessageMap[messageNames.TwitchRaid] = { | |
messageType: 'systemMessage', | |
raidFrom : "SomeUser", | |
raidSize : 42 | |
}; | |
bridge.publish(messageNames.TwitchRaid, raidMessage); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Basically just a typed facade around PubSub, but the basic goal | |
// is the same regardless of the backing implmentation | |
export default class MessageBridge<MessageMap> | |
{ | |
// ... snip | |
public subscribe<MessageName extends keyof MessageMap>( | |
messageName : MessageName, | |
listener : (message : MessageMap[MessageName]) => void | |
} { | |
// ... snip | |
} | |
public publish<MessageName extends keyof MessageMap>( | |
messageName : MessageName, | |
message : MessageMap[MessageName] | |
} { | |
// ... snip | |
} | |
// Nice to have, donno if feasible | |
public buildMessage<MessageName extends keyof MessageMap>( | |
messageName : MessageName, | |
data? : any | |
) : MessageMap[MessageName] { | |
/* build and return an empty message of type, prefilled with the params? Partial<>? */ | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This file has the part I don't know how to do | |
// question at bottom, after context | |
type MessageBase = { | |
messageType: string; | |
shortName: string; | |
}; | |
export type SystemMessage = MessageBase | { | |
messageType: "systemMessage"; | |
}; | |
export type TwitchMessage = MessageBase | { | |
messageType: "twitchMessage"; | |
}; | |
export type ActionRequest = MessageBase | { | |
messageType: "actionRequest"; | |
}; | |
// I'm planning on the below using type merging to keep the | |
// definitions for each message category managable. | |
// excluded for example clarity. | |
interface AppMessageSource { | |
'obs.websocket.connected' : SystemMessage | { | |
shortName: "ObsConnected"; | |
}; | |
'obs.websocket.disconnected' : SystemMessage | { | |
shortName: "ObsDisconnected"; | |
}; | |
// ... snip | |
'twitch.event.raid' : TwitchMessage | { | |
shortName: "TwitchRaid"; | |
raidFrom: string; | |
raidSize: number; | |
}; | |
'twitch.event.follow': TwitchMessage | { | |
shortName: "TwitchFollow"; | |
newFollowerUsername: string; | |
}; | |
// ... snip | |
'overlay.request.changeFilter': { | |
shortName: "OverlayChangeFilter"; | |
source : string; | |
filterName : string; | |
paramChanges : {[paramName : string] : boolean | string | number}; | |
} | |
}; | |
// Something like this? | |
type TrimmedMap<SourceMap> = { | |
[Property in keyof SourceMap]: Omit<SourceMap[Property], "shortName"> | |
}; | |
// Actual used map? | |
export type AppMessageMap : TrimmedMap<AppMessageSource>; | |
// Here is the parts I don't understand how to do. I want to automatically | |
// build an easy to snag listing of shortname -> full message name | |
// using the properties in the map source. Consts, Map object(s), or even a function | |
// that returns the full name based on type would be fine. | |
// I just really really don't want a whole bunch of magic strings running | |
// around. | |
// Something like this would be awesome, except not manually constructed. | |
export const AppMessageNames = { | |
ObsConnected: 'obs.websocket.connected', | |
ObsDisconnected: 'obs.websocket.disconnected', | |
// ... snip, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment