Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript complains when I try to postMessage back to source

Tags:

typescript

This is my code

window.addEventListener('message', (e) => {
  e.source.postMessage('hi there, I hear you!', '*');
});

This is the error:

[ts] Cannot invoke an expression whose type lacks a call signature. Type '((message: any, targetOrigin: string, transfer?: any[]) => void) | ((message: any, transfer?: any[]) => void)' has no compatible call signatures.

When I inspect postMessage it seems to be a method on window and have the signature:

declare function postMessage(
    message: any,
    targetOrigin: string,
    transfer?: any[]
): void;

That looks very much like my call signature to me. So what is wrong with my code?

like image 421
user1283776 Avatar asked Oct 30 '18 12:10

user1283776


2 Answers

e.source is of type MessageEventSource.

type MessageEventSource = WindowProxy | MessagePort | ServiceWorker;

Since only WindowProxy has the method signature you're using, you can guard it with:

window.addEventListener('message', (e) => {
  if (!(e.source instanceof MessagePort) && !(e.source instanceof ServiceWorker)) {
    e.source.postMessage('hi there, I hear you!', '*');
  }
});

Or somehow else tell the TS that your e.source is of type WindowProxy | Window.

like image 58
Roberto Zvjerković Avatar answered Oct 12 '22 00:10

Roberto Zvjerković


The previous answer is correct, however you're risking crashing in not-so-old browsers that do not support MessagePort or ServiceWorker yet. You could check if MessagePort and ServiceWorker exist in the global space using typeof, but that's not good enough for TypeScript static validator. Also it makes the condition complicated unnecessarily.

As alternative I propose checking against Window, which does exist in all browsers and prevents crashing in not-so-old browsers. Event#source can also be null, so that's also implicit in the new condition. And it's just better.

window.addEventListener('message', (e) => {
  if (!(e.source instanceof Window)) return;

  // Use normally.
  e.source.postMessage('hi there, I hear you!', '*');
});
like image 33
José Cabo Avatar answered Oct 12 '22 00:10

José Cabo