Typescript: Service Worker typings

Created on 21 Oct 2016  Â·  21Comments  Â·  Source: microsoft/TypeScript

TypeScript Version: 2.0.3

Types for Service Workers should be built into the default definitions for TypeScript. There are some good examples out there of Service Worker typings from the community.

lib.d.ts Suggestion help wanted

Most helpful comment

It would make things much easier if we could declare a script's environment with triple-slash directives. These could override any configuration that is being used.

@simon-robertson you can, see https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#-reference-lib-

/// <reference lib="webworker" /> 

I did the following and it worked for my needs e.g.:

/// <reference no-default-lib="true"/>
/// <reference lib="es2015" />
/// <reference lib="webworker" />

interface Window extends ServiceWorkerGlobalScope {}

self.addEventListener("fetch", (event: FetchEvent) =>  {
    event.respondWith(caches.match(event.request));
});

All 21 comments

Since service workers run in their own context, i suppose we need --lib serviceworker (similar to --lib webworker).

@zhengbli can we update our declaration files to pull in serviceworker spec idl as well

I think it's necessary to add service worker typings into built-in definitions, though it's still a work-in-progress API.

When I tried to add /// <reference no-default-lib="true"/> directive into service_worker_api to exclude the default lib (like that in lib.webworker.d.ts), I got tons of type missing errors like:

 error TS2304: Cannot find name 'Function'.

So instead I have to use

interface Window extends ServiceWorkerGlobalScope {}

to attach interfaces onto self.

This brings some other problems, eg. I must change the incompatible properties like onmessage into what they are on Window interface:

// expected
interface ServiceWorkerGlobalScope {
    onmessage: (messageevent: ExtendableMessageEvent) => void;
}

// now
interface ServiceWorkerGlobalScope {
    onmessage: (messageevent: MessageEvent) => void;
}

Therefore, I think it would be much better to include service worker typings in default definitions, or, at least there should be a way to make no-default-lib directive act like the built-in ones.

interface Window extends ServiceWorkerGlobalScope {} isn't even working for me.

Anyone know how I can force TS to change the type of self??

Anyone know how I can force TS to change the type of self??

first you need --lib webworker to include the webworker library definition. self is defined as declare var self: WorkerGlobalScope;. so update the declaration of WorkerGlobalScope to get what you want.

I can't vouch for it, but scouting about it looks like this gist is updating pretty regularly. May be a good candidate for TS to adopt?

I really don't like this type of comments, but... Any updates here? I mean, this is just a definition file with a proper compiler flag, isn't it? Maybe we won't be writing service workers in Typescript, but Typescript definitions are really important now days in Javascript development, for me at least. :P.

PRs welcomed. the files are generated https://github.com/Microsoft/TSJS-lib-generator. I would be happy to help if someone wants to pick this issue up.

I wrote an updated gist from the one linked above by @rektide here: Service Worker Typings to Supplement lib.webworker.d.ts.

It's intended to be included by a triple slash directive in the service worker, and registration scripts. It works well for me using the webworker lib along with es5+. Hope this helps

I feel like I'm completely missing something. I tried a couple of the type definition files and they're pretty much missing everything I need. addEventListener isn't declared to take a callback that takes a ServiceWorkerMessageEvent. And ServiceWorkerMessageEvent doesn't have the properties I'm using (request, waitUntil, respondWith). self is missing everything since it's still defined as a WorkerGlobalScope.

And to further add to my confusion this says that the dom lib now has service worker stuff: https://www.npmjs.com/package/@types/service_worker_api Why would that be? I didn't think there was a DOM inside service workers. Also, I tried it and it didn't work.

Is there something else I need to configure or include somewhere?

Pending an update on this, I've just switched my service worker code into vanilla JS. Though types would be great for development, this is a basic failing of TypeScript currently.

I'm addressing the issue like this. Currently works well.

https://gist.github.com/shqld/32df51a4a4ed429f2c76e4e2cfdf6f96#gistcomment-2793376

And created a package https://github.com/shqld/types-serviceworker

(If this violates licenses, please tell me)

@caseyhoward The PR removing Service Worker API is https://github.com/DefinitelyTyped/DefinitelyTyped/pull/14786 Agreed, the "dom lib" message is incorrect. I got it seemingly working with --lib es6,webworker as explained in https://github.com/Microsoft/TypeScript/issues/14877#issuecomment-340279293

@shqld Thanks for this! Edit: I've tried both methods. Many hacks are required to use the webworker library and types-serviceworker just works.

For anyone else who comes upon this thread, there seems to be 2 main solutions:

  1. Use the https://github.com/shqld/types-serviceworker package by @azarashd, with the triple-slash directives to include the typings. Note that you can only use these if you don't have { "lib": ["dom"] } declared

  2. Follow this StackOverflow reply by Jake Archibald (one of the main Chrome engineers who worked on Service Workers) to break your project into multiple tsconfig files. One of the tsconfig files will only include the { "lib": ["webworker"] } for the Service Worker and one will only include { "lib": ["dom"] } for the normal site. The file also needs to declare var self: ServiceWorkerGlobalScope; export {}; to fix the scope as a hack

A few additional notes:

I had a setup where the broader project had many typings installed via @types/*. By default, all of these typings are included. However, many typings assume that your tsconfig includes { "lib": ["dom"] } already and return type errors without them.

To ensure that this works, make sure you include { "types": [] } to not include the typings by default. Instead, only include typings you use in the tsconfig project with the Service Worker.

It would make things much easier if we could declare a script's environment with triple-slash directives. These could override any configuration that is being used.

/// env node
/// env worker
/// env serviceworker

ESLint provides a similar solution.

/* eslint-env node */
/* eslint-env worker */
/* eslint-env serviceworker */

Most of the development teams that I know tend to push TS scripts through Babel and Webpack, and need a simple way to target multiple environments in one TS code base so VSCode (and friends) can provide the correct APIs (code hints etc).

The way the service worker issue was resolved here was by adding "webworker" to the tsconfig lib array, and then wrapping the service worker code in a function.

const initialize = (service: ServiceWorkerGlobalScope): void => {
    service.addEventListener("install", ... )
}

initialize(self as any)

Not ideal, because the service worker APIs are now picked up by all of the scripts in the project, but at least this way we have access to the service worker type definitions.

It would make things much easier if we could declare a script's environment with triple-slash directives. These could override any configuration that is being used.

@simon-robertson you can, see https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#-reference-lib-

/// <reference lib="webworker" /> 

It would make things much easier if we could declare a script's environment with triple-slash directives. These could override any configuration that is being used.

@simon-robertson you can, see https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html#-reference-lib-

/// <reference lib="webworker" /> 

I did the following and it worked for my needs e.g.:

/// <reference no-default-lib="true"/>
/// <reference lib="es2015" />
/// <reference lib="webworker" />

interface Window extends ServiceWorkerGlobalScope {}

self.addEventListener("fetch", (event: FetchEvent) =>  {
    event.respondWith(caches.match(event.request));
});

I did the following and it worked for my needs e.g.:

/// <reference no-default-lib="true"/>
/// <reference lib="es2015" />
/// <reference lib="webworker" />

interface Window extends ServiceWorkerGlobalScope {}

self.addEventListener("fetch", (event: FetchEvent) =>  {
    event.respondWith(caches.match(event.request));
});

Short of breaking up a project into multiple workspace projects, I guess that would be the best solution for now. I was thinking of something more along the lines of ...

/// <environment type="dedicatedworker" /> or
/// <environment type="serviceworker" /> or
/// <environment type="audioworklet" /> and so on

Essentially overriding the libraries specified in the tsconfig.json file for isolated use cases.

Which lib I need for InstallEvent ?

…videlicet…

I added "webworker" into local config json and it perfectly worked with ServiceWorkerGlobalScope ExtendableEvent PushEvent SyncEvent , … but still have error (2304) in InstallEvent

InstallEvent code looks like:

sw.addEventListener( 'install', function ( /** @type {InstallEvent} */ event )
{
    //…
});

where sw is instance of ServiceWorkerGlobalScope

Someone understand it? Do I missing some lib for InstallEvent?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

siddjain picture siddjain  Â·  3Comments

weswigham picture weswigham  Â·  3Comments

Zlatkovsky picture Zlatkovsky  Â·  3Comments

dlaberge picture dlaberge  Â·  3Comments

jbondc picture jbondc  Â·  3Comments