1+ // eventBus.ts
2+ import { reactive } from 'vue'
3+
4+ type EventCallback = ( ...args : any [ ] ) => void
5+ type EventDefinition = Record < string , any [ ] >
6+
7+ // Generic event bus creator function - similar to defineEmits pattern
8+ export function defineEventBus < T extends EventDefinition > ( events : T = { } as T ) {
9+ // Type for event callbacks mapped to their parameter types
10+ type EventCallbacks = {
11+ [ K in keyof T ] : ( ...args : T [ K ] ) => void
12+ }
13+
14+ // Type-safe event listeners storage
15+ const listeners : {
16+ [ K in keyof T ] ?: EventCallbacks [ K ] [ ]
17+ } = { }
18+
19+ const bus = reactive ( {
20+ // Register event listener with type checking
21+ on < K extends keyof T > ( event : K , callback : EventCallbacks [ K ] ) {
22+ if ( ! listeners [ event ] ) {
23+ listeners [ event ] = [ ]
24+ }
25+ listeners [ event ] ! . push ( callback )
26+ return ( ) => bus . off ( event , callback )
27+ } ,
28+
29+ // Remove event listener
30+ off < K extends keyof T > ( event : K , callback ?: EventCallbacks [ K ] ) {
31+ if ( ! listeners [ event ] ) return
32+ if ( ! callback ) {
33+ delete listeners [ event ]
34+ return
35+ }
36+ listeners [ event ] = listeners [ event ] ! . filter ( cb => cb !== callback )
37+ } ,
38+
39+ // Emit event with type-checked arguments
40+ emit < K extends keyof T > ( event : K , ...args : T [ K ] ) {
41+ if ( ! listeners [ event ] ) return
42+ listeners [ event ] ! . forEach ( callback => callback ( ...args ) )
43+ }
44+ } )
45+
46+ return bus
47+ }
48+
49+ // Usage example: create a typed event bus
50+ export type GlobalEvents = {
51+ 'searchbar-update' : [ value : string ]
52+ }
53+
54+ // Create a global instance
55+ export const globalEventBus = defineEventBus < GlobalEvents > ( )
56+
57+
58+ // In component A.vue
59+ // Usage example
60+ // import { globalEventBus } from './eventBus'
61+
62+ // function userLogin() {
63+ // // Type checking ensures correct parameters
64+ // globalEventBus.emit('user:login', 'john_doe', Date.now())
65+
66+ // // This would cause a TypeScript error - wrong parameter types
67+ // // globalEventBus.emit('user:login', 123, 'wrong')
68+ // }
69+
70+ // // In component B.vue
71+ // import { globalEventBus } from './eventBus'
72+ // import { onMounted, onUnmounted } from 'vue'
73+
74+ // const loginHandler = (username: string, timestamp: number) => {
75+ // console.log(`${username} logged in at ${new Date(timestamp).toLocaleString()}`)
76+ // }
77+
78+ // onMounted(() => {
79+ // // Store the unsubscribe function
80+ // const unsubscribe = globalEventBus.on('user:login', loginHandler)
81+
82+ // // Alternative cleanup approach
83+ // onUnmounted(() => {
84+ // unsubscribe()
85+ // // Or: globalEventBus.off('user:login', loginHandler)
86+ // })
87+ // })
0 commit comments