Repository navigation
Service Worker typings #11781
Description
Activity
- addedDomain: lib.d.tsThe issue relates to the different libraries shipped with TypeScriptThe issue relates to the different libraries shipped with TypeScriptSuggestionAn idea for TypeScriptAn idea for TypeScript
on Oct 21, 2016 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
Reacted by Tyson Matanich, Brandon Bennett and Kevin CoxI 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 inlib.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
onmessageinto what they are onWindowinterface:// 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-libdirective act like the built-in ones.Reacted by barinbritva, val1991 and Roman OrlowskiReacted by barinbritvainterface 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 webworkerto include the webworker library definition.selfis defined asdeclare var self: WorkerGlobalScope;. so update the declaration ofWorkerGlobalScopeto get what you want.Reacted by Albert MañosaI 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.
Reacted by Michael Leonard, Colin Bradley, Objektwerks, electrovir and Albert MañosaPRs 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
Reacted by Tar22 remaining items
The simplest solution that worked for me, is just this on the Service Worker code:
/// <reference lib="WebWorker" /> const sw: ServiceWorkerGlobalScope = self as any
Reacted by Greg, Brandon Bennett and Jesper van den EndeReacted by Jesper van den EndeTo avoid aliasing
self, this seems to work in the latest version of TypeScript:/// <reference lib="WebWorker" /> declare let self: ServiceWorkerGlobalScope;
Reacted by Wagner, Brandon Bennett, Žilvinas Rudžionis and Germán PinedaTo 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 😆
Reacted by Brandon Bennett, Daniel Rotärmel, Samuel Plumppu, Loïc Boset, Oleg Lysachok, Pavlo Zalutskiy, Julien Maulny and Andrei KarushevReacted by Loïc Boset, samausir and Andrei KarushevReacted by JeanGeThis 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",
Reacted by Michał MiszczyszynReacted by Noel SchenkIvo Cazemier (@icazemier) ty :) adding to tsconfig.json:
"lib": ["WebWorker", ...],
did it for meReacted by Ivo CazemierReacted by Steven Cochrane and SovLynSomehow
libdoesn’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.jsonfiles, though that would somewhat complicate build process and it’s unclear whether it’ll even work.Reacted by Kastriot LimaniIf you are using Vite (@vitejs), this works for me
- 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' } }, }, },
- Add to the tsconfig.app.json file
"compilerOptions": { "lib": [ "WebWorker" ],
- Create the src/sw.ts file and add this code
declare const self: ServiceWorkerGlobalScope; self.addEventListener('install', (e: ExtendableEvent) => { ... });
Reacted by Mathieu RousseauI got it working with this at the top of my worker code
/// <reference lib="WebWorker" /> export type {} declare let self: DedicatedWorkerGlobalScope
Reacted by Paulo and SelfMadeSystemReacted by Paulo and SelfMadeSystemIt seems typings are missing for
InstallEventand thus there are no types for https://developer.mozilla.org/en-US/docs/Web/API/InstallEvent/addRoutes
Reacted by simonghpubGugustinette (@Gugustinette) solution worked for me to get
self.onconnectfrom 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.onconnectwith the tsconfig.json lib specified becomes an error if I remove the reference comment. So confused!Reacted by GugustinetteAdam 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).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: falsefor code that doesn't ever need to be emitted.Abdur-Rahman (@ShafSpecs) and Gugustinette (@Gugustinette) solutions break Firefox compatibility because this issue breaks any ServiceWorker scripts that are use
exportorimport. 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
_selfin place ofselfin the ServiceWorker.This is ugly and
skipLibCheckmay degrade type accuracy, but I haven't found any other way to support Firefox with this nasty combination of long-running issues.Reacted by GugustinetteIs 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?
Reacted by Gugustinette, Kabir Brar and Timothy TottenThis 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?
Reacted by GugustinetteReacted by Anton Strogonoff
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.