Skip to content

Service Worker typings #11781

Description

@jgw96

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.

Activity

  1. mhegazy commented on Oct 21, 2016

    @mhegazy
    Contributor

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

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

  2. dolphin-wood commented on Jan 1, 2017

    @dolphin-wood

    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.

  3. code-tree commented on Jan 19, 2017

    @code-tree

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

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

  4. mhegazy commented on Jan 25, 2017

    @mhegazy
    Contributor

    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.

  5. rektide commented on Jun 16, 2017

    @rektide

    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?

  6. michaeljota commented on Mar 13, 2018

    @michaeljota

    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.

  7. mhegazy commented on Apr 3, 2018

    @mhegazy
    Contributor

    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.

  8. added this to the milestone on Apr 3, 2018
  9. tiernan commented on Apr 13, 2018

    @tiernan

    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

  10. caseyhoward commented on Nov 2, 2018

    @caseyhoward

    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?

  11. jhpratt commented on Dec 3, 2018

    @jhpratt

    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.

  12. shqld commented on Dec 23, 2018

    @shqld

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

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

  13. 22 remaining items

  14. alexbruno commented on Jan 3, 2023

    @alexbruno

    The simplest solution that worked for me, is just this on the Service Worker code:

    /// <reference lib="WebWorker" />
    
    const sw: ServiceWorkerGlobalScope = self as any
  15. F2 commented on Feb 26, 2023

    @F2

    To avoid aliasing self, this seems to work in the latest version of TypeScript:

    /// <reference lib="WebWorker" />
    
    declare let self: ServiceWorkerGlobalScope;
  16. ShafSpecs commented on Mar 28, 2023

    @ShafSpecs

    To avoid aliasing self, this seems to work in the latest version of TypeScript:

    /// <reference lib="WebWorker" />
    
    declare let self: ServiceWorkerGlobalScope;

    It gives an error:

    Cannot redeclare block-scoped variable 'self'

    Using this instead worked:

    /// <reference lib="WebWorker" />
    
    export type {};
    declare let self: ServiceWorkerGlobalScope;

    Yep, it's getting weirder 😆

  17. icazemier commented on Mar 29, 2023

    @icazemier

    This works for me (for now... 🤷🏻 ):

    /// <reference lib="esnext" />
    /// <reference lib="webworker" />
    /// <reference no-default-lib="true"/>
    
    // service-worker.ts
    (() => {
    
      const initializeSW = (sw: ServiceWorkerGlobalScope) => {
        sw.addEventListener('install', (event: ExtendableEvent) => {
          // eslint-disable-next-line no-console
          console.log(event);
        });
    
        // see: https://developer.mozilla.org/en-US/docs/Web/API/Clients/claim
        sw.addEventListener('activate', (event: ExtendableEvent) => {
          // eslint-disable-next-line no-console
          console.log(event);
          event.waitUntil(sw.clients.claim());
        });
    
      };
    
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      initializeSW(self as any);
    })();

    tsconfig:

    {
      "compilerOptions": {
        "allowJs": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true,
        "esModuleInterop": true,
        "strictNullChecks": true,
        "useUnknownInCatchVariables": false,
        "lib": ["WebWorker", "ESNext"],
        "noEmit": true,
        "strict": true,
        "outDir": "./public/sw",
        "module": "esnext",
        "target": "esnext",
        "incremental": false,
        "sourceMap": true,
        "isolatedModules": false,
        "moduleResolution": "node",
        "resolveJsonModule": true
      },
      "include": ["service-worker.ts"],
      "exclude": ["node_modules"]
    }
    
    "typescript": "^5.0.2",
  18. noel-schenk commented on Mar 26, 2024

    @noel-schenk

    Ivo Cazemier (@icazemier) ty :) adding to tsconfig.json:

    "lib": ["WebWorker", ...],
    did it for me

  19. strogonoff commented on Sep 30, 2024

    @strogonoff

    Somehow lib doesn’t work for me, but Ivo Cazemier (@icazemier)’s

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

    preamble, together with declare const self: ServiceWorkerGlobalScope;, seems to do the trick but unfortunately due to #19978 it breaks other sibling modules that do run in DOM context.

    It would be an imperfect a good solution otherwise, with the added benefit of disabling the DOM or other libs that would have no effect in service worker context.

    I plan to try addressing this later by having multiple sub-projects with dedicated tsconfig.json files, though that would somewhat complicate build process and it’s unclear whether it’ll even work.

  20. hatem-amer commented on Oct 30, 2024

    @hatem-amer

    If you are using Vite (@vitejs), this works for me

    1. Add to the vite.config.ts file
    build: {
        rollupOptions: {
            input: {
                app: './index.html',
                'sw': './src/sw.ts',
            },
            output: {
                entryFileNames: assetInfo => {
                    return assetInfo.name === 'sw' ? '[name].js' : 'assets/[name]-[hash].js'
                }
            },
        },
    },
    1. Add to the tsconfig.app.json file
    "compilerOptions": {
        "lib": [
          "WebWorker"
        ],
    1. Create the src/sw.ts file and add this code
    declare const self: ServiceWorkerGlobalScope;
    
    self.addEventListener('install', (e: ExtendableEvent) => {
      ...
    });
  21. Gugustinette commented on Dec 22, 2024

    @Gugustinette

    I got it working with this at the top of my worker code

    /// <reference lib="WebWorker" />
    export type {}
    declare let self: DedicatedWorkerGlobalScope
  22. arianvp commented on Apr 9, 2025

    @arianvp

    It seems typings are missing for InstallEvent

    and thus there are no types for https://developer.mozilla.org/en-US/docs/Web/API/InstallEvent/addRoutes

  23. eighty4 commented on Aug 8, 2025

    @eighty4

    Gugustinette (@Gugustinette) solution worked for me to get self.onconnect from SharedWorkerGlobalScope. Why does /// <reference lib="WebWorker" /> work to access SharedWorkerGlobalScope but tsconfig.json's "lib": ["WebWorker"] does not?

    /// <reference lib="WebWorker" />
    declare let self: SharedWorkerGlobalScope
    
    
    self.onconnect = (e: MessageEvent) => {
    

    self.onconnect with the tsconfig.json lib specified becomes an error if I remove the reference comment. So confused!

  24. strogonoff commented on Aug 11, 2025

    @strogonoff

    Adam McKee (@eighty4) do you have only one tsconfig.json? Do you use it with TSC directly or with some other tooling that respects tsconfig.json (e.g., esbuild, VSC, etc.)? Make sure the tsconfig.json that you think has effect indeed has effect, and you don’t accidentally override something through tsconfig inheritance.

    Note that if you share that tsconfig in a project where you also have non-worker code, and you add WebWorker to lib, worker types will apply in non-worker code, which will confuse type validation (e.g., self.onconnect will not raise an error if you use it in your main browser window).

  25. eighty4 commented on Sep 1, 2025

    @eighty4

    I've since solved it with project references to scope libs to specific code. First time using project references within one webapp and for refs between packages of a monorepo.

    I was sad to find that the project references feature can't be hijacked within a bundler built webapp codebase to control the self scope and APIs available for window and worker portions of the app because you would need to add noEmit: false for code that doesn't ever need to be emitted.

  26. FusillyCode commented on Oct 7, 2025

    @FusillyCode

    Abdur-Rahman (@ShafSpecs) and Gugustinette (@Gugustinette) solutions break Firefox compatibility because this issue breaks any ServiceWorker scripts that are use export or import. Here is what worked for me:
    In the tsconfig file, add:

    "compilerOptions": {
      "skipLibCheck": true
    }
    

    In the ServiceWorker script, add:

    /// <reference lib="WebWorker" />
    /// <reference lib="es6" />
    /// <reference no-default-lib="true"/>
    const _self = (self as unknown) as ServiceWorkerGlobalScope

    Then, use _self in place of self in the ServiceWorker.

    This is ugly and skipLibCheck may degrade type accuracy, but I haven't found any other way to support Firefox with this nasty combination of long-running issues.

  27. vadimmos commented on Apr 7, 2026

    @vadimmos

    Is there any progress on this issue? Are developers still doomed to write ServiceWorker code with one eye on the documentation, without the ability to rely on autocompletion and type checking tools?

  28. supernovus commented on May 14, 2026

    @supernovus

    This issue will be 10 years old in a few months! Service Workers are used extensively, and yet they still aren't supported properly by TypeScript (and in turn the JS language server in VSCode). The various workarounds are ridiculous and lead to ugly code that is much more difficult to maintain.

    So is this just a matter of nobody bothering to do it? Like if someone forked the code, added a 'serviceworker' lib definition separate from 'webworker', and then submitted a pull request, would it actually get merged?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Domain: lib.d.tsThe issue relates to the different libraries shipped with TypeScriptHelp WantedYou can do thisSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions