Skip to content

Enhance typing of postMessage in Service Workers #25176

Closed
@nikeee

Description

@nikeee

Search Terms

  • postMessage
  • Transferable
  • structuredserialize, structured serialize
  • use-after-transfer
  • service worker

Suggestion

The Service Worker APIs come with a mthod postMessage (e.g. window.postMessage). Three things:

  1. The parameter message is processed using the structured clone algorithm, which requires the value to
    satisfy certain constrains: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm

    • Current type of message: any
    • The algorithm prohibits passing these values for message (or an object containing these values):
      • Errors and Functions
      • DOM nodes
    • There is a list of all allowed types. However:
      • No symbols
      • only plain objects (e.g. from object literals)
    • While I think that it would be possible to constrain the message type from any to something more specific, I don't know if there is a way to constrain the object requirements.
    • any allows passing not-serializable data
    • Suggestion: Constrain the type of message
    • Additional suggestion: Constrain the type of MessageEvent#data
  2. There is a Transferable interface which is used to provide transfering objects instead of copying them.

    • It has no specific properties or methods
    • It is currently implemented by: ArrayBuffer, MessagePort, ImageBitmap
    • Tricky: As Transferable is basically an empty interface
    • any allows passing not-transferable data
    • Suggestion: Constrain the type of transfer/transferList to ArrayBuffer | MessagePort | ImageBitmap (or find another way of constraining the type)
  3. A transfered object cannot be used after it was transferred (e.g. using postMessage())

    • Suggestion: Introduce a diagnostic for use-after-transfer of a variable to warn the user

Use Cases

  • For 1: Prevents accidental passing of an object containing not-serializable data. Prevents an exception during runtime (DATA_CLONE_ERR).
  • For 2: Prevents passing a value of the wrong type that does not implement the interface.
  • For 3: Prevents accidental use of value after it was transfered.

Examples

1.:
These errors could be prevented (all valid according to the current definitions):

window.postMessage({
	f() {
		alert("hi!");
	}
}, "*");

window.postMessage({
	e: document.createElement("div"),
}, "*");

window.postMessage({
	s: Symbol(":("),
}, "*");

window.postMessage(class foo { }, "*");

2.:
This error could be prevented:

window.postMessage({ }, "*", [ { foo: 42 } /* objects are not transferable */]);
// -> Uncaught TypeError: Failed to execute 'postMessage' on 'Window':
// Value at index 0 does not have a transferable type.

3.:
This unintentional use-after-transfer could be prevented / pointed at:

const bar = new ArrayBuffer(42);

window.postMessage({a: 13}, "*", [bar]);

// Prints 0, because it was used after transfer (presumably not the intention of the user)
console.log(bar.byteLength); 

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript / JavaScript code
    • Well, it would break if it surfaces previously undetected type errors
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. new expression-level syntax)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Domain: lib.d.tsThe issue relates to the different libraries shipped with TypeScriptFixedA PR has been merged for this issueHelp WantedYou can do thisSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions