const channel = new BroadcastChannel('foo');
channel.postMessage(<any>);
我知道有一个库(https://github.com/pubkey/broadcast-channel#create-a-typed-channel-in-typescript),但我不想包含任何额外的依赖关系,我只是想让打字稿在编译时检查消息的类型
import { BroadcastChannel } from 'broadcast-channel';
declare type Message = {
foo: string;
};
const channel: BroadcastChannel<Message> = new BroadcastChannel('foobar');
channel.postMessage({
foo: 'bar'
});
您可以创建一个扩展原生
BroadcastChannel
的自定义类,使 postMessage
方法严格键入:
export class StrictBroadcastChannel<
MessageType extends Record<string, any>,
> extends BroadcastChannel {
public postMessage(message: MessageType): void {
return super.postMessage(message)
}
}
用途:
type MessageType =
| { type: 'hello', user: string }
| { type: 'goodbye' }
const channel = new StrictBroadcastChannel<MessageType>()
channel.postMessage({ type: 'hello' }) // TypeError: missing "user"
channel.postMessage({ type: 'goodbye' }) // OK
您可以从这里开始,按照您喜欢的方式复杂化。我将消息结构嵌入到类本身中,因此所有消息都具有
{ type: string, payload?: unknown }
形状,然后我创建一个消息映射,如下所示:
interface DataMessageMap {
DATA_START(clientId: string): void
DATA_CHUNK(chunk: string): void
DATA_END(): void
}
虽然 kettanaito 的答案提供了 postMessage 的类型,但它不提供侦听器端的类型安全(
onmessage
)。此外,如果您只需要编译时类型检查,则类继承会产生额外的开销。
幸运的是,BroadcastChannel 是在 Typescript 的 DOM 类型中输入的。
基于上面的接口定义,我创建了以下泛型类型的 BroadcastChannel 定义:
interface StrictBroadcastChannelEventMap<T> {
"message": MessageEvent<T>;
"messageerror": MessageEvent<T>;
}
export interface StrictBroadcastChannel<T> extends EventTarget {
readonly name: string;
onmessage: ((this: BroadcastChannel, ev: MessageEvent<T>) => any) | null;
onmessageerror: ((this: BroadcastChannel, ev: MessageEvent<T>) => any) | null;
close(): void;
postMessage(message: T): void;
addEventListener<K extends keyof StrictBroadcastChannelEventMap<T>>(type: K, listener: (this: BroadcastChannel, ev: StrictBroadcastChannelEventMap<T>[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof StrictBroadcastChannelEventMap<T>>(type: K, listener: (this: BroadcastChannel, ev: StrictBroadcastChannelEventMap<T>[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
然后您可以使用以下代码进行编译时检查:
type ControlMessage = {
type: 'showVideo';
videoUrl: string;
} | {
type: 'closeVideo'
}
const bc: StrictBroadcastChannel<ControlMessage> = new BroadcastChannel('my_channel');
bc.onmessage = function(ev) {
switch (ev.data.type) { // Automatic code completion when access ev.data
case 'showVideo':
console.log('showVideo', ev.data.videoUrl);
break;
case 'closeVideo':
console.log('closeVideo');
break;
}
}
bc.postMessage({ type: 'showVideo', videoUrl: 'https://example.com/1.mp4' }); // OK
bc.postMessage({ type: 'closeVideo', extraKey: 1 }); // Error: 'extraKey' does not exist in type