事件总线中回调参数的打字稿类型
Typescript types for arguments of a callback in an event bus
使用我们自制的事件总线,我们收到以下 TS 错误:
TS2345: Argument of type 'unknown' is not assignable to parameter of type 'AccountInfo | undefined'.
Type 'unknown
事件总线使用类型 unknown[]
作为回调函数的参数。当然不可能在事件总线的参数中设置所有可能的类型。所以我们在如何让 TypeScript 正确推断参数类型或者是否有其他解决方案上有点卡住了?
// eventBus.ts
type TCallBack = (...args: unknown[]) => boolean | void
const subscriptions: { [key: string]: TCallBack[] } = {}
interface ISubscription {
eventName: string
callback: TCallBack
}
export function unsubscribe({ eventName, callback }: ISubscription) {
if (!subscriptions[eventName]) { return }
const index = subscriptions[eventName].findIndex((l) => l === callback)
if (index < 0) { return }
subscriptions[eventName].splice(index, 1)
}
export function subscribe({ eventName, callback }: ISubscription) {
if (!subscriptions[eventName]) { subscriptions[eventName] = [] }
subscriptions[eventName].push(callback)
return () => unsubscribe({ eventName, callback })
}
export function publish(eventName: string, ...args: unknown[]) {
if (!subscriptions[eventName]) { return }
for (const callback of subscriptions[eventName]) {
const result = callback(...args)
if (result === false) { break }
}
}
在应用程序的某个时刻,我们发布 login
事件来触发所有订阅者:
// authServce.ts
publish('login', account)
之后触发订阅者:
// authStore.ts
export const setAccount = (account?: AuthenticationResult['account']) => {
if (account) state.account = account
else state.account = defaultState().account
console.log('setAccount: ', state.account)
}
subscribe({
eventName: 'login',
callback: (account) => {
setAccount(account)
},
})
此代码可以完美运行,但如果能够解决 TS 错误就更好了。
扩展any
并将默认设置为any
(这样你就不需要每次都指定类型)
// eventBus.ts
type TCallBack<T extends any = any> = (...args: T[]) => boolean | void
const subscriptions: { [key: string]: TCallBack[] } = {}
interface ISubscription<T> {
eventName: string
callback: TCallBack<T>
}
export function unsubscribe<T>({ eventName, callback }: ISubscription<T>) {
if (!subscriptions[eventName]) { return }
const index = subscriptions[eventName].findIndex((l) => l === callback)
if (index < 0) { return }
subscriptions[eventName].splice(index, 1)
}
export function subscribe<T>({ eventName, callback }: ISubscription<T>) {
if (!subscriptions[eventName]) { subscriptions[eventName] = [] }
subscriptions[eventName].push(callback)
return () => unsubscribe({ eventName, callback })
}
export function publish<T>(eventName: string, ...args: T[]) {
if (!subscriptions[eventName]) { return }
for (const callback of subscriptions[eventName]) {
const result = callback(...args)
if (result === false) { break }
}
}
使用我们自制的事件总线,我们收到以下 TS 错误:
TS2345: Argument of type 'unknown' is not assignable to parameter of type 'AccountInfo | undefined'.
Type 'unknown
事件总线使用类型 unknown[]
作为回调函数的参数。当然不可能在事件总线的参数中设置所有可能的类型。所以我们在如何让 TypeScript 正确推断参数类型或者是否有其他解决方案上有点卡住了?
// eventBus.ts
type TCallBack = (...args: unknown[]) => boolean | void
const subscriptions: { [key: string]: TCallBack[] } = {}
interface ISubscription {
eventName: string
callback: TCallBack
}
export function unsubscribe({ eventName, callback }: ISubscription) {
if (!subscriptions[eventName]) { return }
const index = subscriptions[eventName].findIndex((l) => l === callback)
if (index < 0) { return }
subscriptions[eventName].splice(index, 1)
}
export function subscribe({ eventName, callback }: ISubscription) {
if (!subscriptions[eventName]) { subscriptions[eventName] = [] }
subscriptions[eventName].push(callback)
return () => unsubscribe({ eventName, callback })
}
export function publish(eventName: string, ...args: unknown[]) {
if (!subscriptions[eventName]) { return }
for (const callback of subscriptions[eventName]) {
const result = callback(...args)
if (result === false) { break }
}
}
在应用程序的某个时刻,我们发布 login
事件来触发所有订阅者:
// authServce.ts
publish('login', account)
之后触发订阅者:
// authStore.ts
export const setAccount = (account?: AuthenticationResult['account']) => {
if (account) state.account = account
else state.account = defaultState().account
console.log('setAccount: ', state.account)
}
subscribe({
eventName: 'login',
callback: (account) => {
setAccount(account)
},
})
此代码可以完美运行,但如果能够解决 TS 错误就更好了。
扩展any
并将默认设置为any
(这样你就不需要每次都指定类型)
// eventBus.ts
type TCallBack<T extends any = any> = (...args: T[]) => boolean | void
const subscriptions: { [key: string]: TCallBack[] } = {}
interface ISubscription<T> {
eventName: string
callback: TCallBack<T>
}
export function unsubscribe<T>({ eventName, callback }: ISubscription<T>) {
if (!subscriptions[eventName]) { return }
const index = subscriptions[eventName].findIndex((l) => l === callback)
if (index < 0) { return }
subscriptions[eventName].splice(index, 1)
}
export function subscribe<T>({ eventName, callback }: ISubscription<T>) {
if (!subscriptions[eventName]) { subscriptions[eventName] = [] }
subscriptions[eventName].push(callback)
return () => unsubscribe({ eventName, callback })
}
export function publish<T>(eventName: string, ...args: T[]) {
if (!subscriptions[eventName]) { return }
for (const callback of subscriptions[eventName]) {
const result = callback(...args)
if (result === false) { break }
}
}