Typescript: Unable to access ServiceWorkerGlobalScope via `self.`

Created on 27 Mar 2017  路  21Comments  路  Source: microsoft/TypeScript



Since ServiceWorker related types sit in lib.webworker.d.ts, webworker lib need to be added to tsconfig.json.

{
  "compilerOptions": {
    "lib": [
      "es2017",
      "webworker"
    ]
  }
}

But in current lib.webworker.d.ts, it declare var self: WorkerGlobalScope;, so we can't access ServiceWorkerGlobalScope via self.


TypeScript Version: 2.2.1

Expected behavior:

Can access ServiceWorkerGlobalScope via self.(like self.clients)

Actual behavior:

Access with error.

image

Bug lib.d.ts help wanted

Most helpful comment

It feels like TypeScript needs to break the various worker types apart in its definitions. This isn't just a service worker issue, it's an issue for other contexts that have a different global, like shared workers & the various worklets.

Either that, or there should be a way to declare which interface is the global.

The various self hacks in this thread only work for references to self. You've still got incorrect types for the global.

All 21 comments

I have not found references in the sepec that self is of type ServiceWorkerGlobalScope.

I think clients should be available as a global variable though. i.e.:

declare var clients: Clients;

PRs welcomed. You can find more information about contributing lib.d.ts fixes at https://github.com/Microsoft/TypeScript/blob/master/CONTRIBUTING.md#contributing-libdts-fixes.

self property will return browsing context object. And according to MDN, sometimes return ServiceWorkerGlobalScope object. See following docs.

I'm wondering whether we need to separate typings of web worker and service worker for the following reasons:

  1. If we put all worker typings into one lib, How can we prevent web worker user using service worker methods and properties like clients.
  2. close is not accessible in service worker, how can we omit close in ServiceWorderGlobalScope?
  3. We can access service worker methods and properties like clients registration via self in Chrome 57.(Just like the self in Window)

image

As a workaround I am currently doing this

(function (self: ServiceWorkerGlobalScope) {
   //Service worker contents...
})(<ServiceWorkerGlobalScope>self);

Anyone have a better solution?

Any progress about this? It's kinda sad that we cannot use Service Workers alongside Type Script.

I did this:

const { clients, addEventListener, skipWaiting, registration } = self as ServiceWorkerGlobalScope;

Note you need "webworker" lib with 2.4

Adding declare var self: ServiceWorkerGlobalScope; on top of my service worker implementation fixes that

@abarisain I came up with your solution as well but it fails with following error

Variable 'self' must be of type 'WorkerGlobalScope', but here has type 'ServiceWorkerGlobalScope'.

How did you configure your tsconfig.json to have it working? Thanks!

The workaround I found was:

const _self = self as ServiceWorkerGlobalScope;

...but you then have to use _self everywhere :(

Are you using the latest typescript version?

Turns out since I commented, my needs evolved: I needed to define new variables on the global scope.
Since my project mixes a lot of environments, I also had to have many sub .tsconfig files.

Here is what works for me:

/// <reference path='../../../node_modules/typescript/lib/lib.es6.d.ts' />
/// <reference path='../../../node_modules/typescript/lib/lib.webworker.d.ts' />
/// <reference path="../../types/contextual/serviceworker-patches.d.ts" />

import { foo } from './bar'
declare var self: MyWorkerGlobalScope;
interface MyWorkerGlobalScope extends ServiceWorkerGlobalScope {
  handleForwardedEvent?: (eventName: string, event: Event) => Promise<void>;
}

serviceworker-patches.d.ts has some other patches to fix the incomplete definitions

here is my tsconfig

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "lib": ["es6"]
  }
}

(the extend part is irrelevant, as all options defined in my base tsconfig are for other stuff)

Thanks for your very fast answer :)

I was stucked with 2.3.4 for other parts of the project but switching to 2.5.2 did not solve my compile error. I am always very confused with the triple-slash thing... and how it relates to adding libs in tsconfig.json

"lib": [
            "webworker",
            "es2016"
        ],

Nevermind, I will remain with my trick... it does the job as well... Hopefully, I will eventually understand those nasty typing issues... not speaking about how to tell the IDE that this file/folder is a service worker while the rest is in the context of Window etc... But this is more a debate for stackoverflow than this issues database.

The triple slashes are exactly how I tell that a file is a service worker :) it overrides every "lib" entry, but it's quite a dirty hack.
I think you should isolate your worker in its own subfolder

Here is what worked for me:

  • in tsconfig.json:
{
  "compilerOptions": {
    "lib": [
      "es6",
      "webworker",
      "dom"
    ]
  }
}
  • in the service worker:
import { } from ".";
declare var self: ServiceWorkerGlobalScope;

Not sure why the empty import is required :man_shrugging:

@Tetr4

Not sure why the empty import is required

I assume to mark file as a module. Without import/export statements TS doesn't mark file as a module.

@Tetr4 using an empty import caused an error for me:

Cannot find module '.'.

Adding export default null instead of import { } from "." in the service worker silenced the error.

@Tetr4 I got errors using your approach as I then got duplicated references between dom and webworker.

I ended up having to build a referenced tsconfig.json with two library configs (kind of like this), which seemed to work ok, but then with export default null at the top, that was copied into my JavaScript output as exports.__esModule and caused errors during registration.

So, I still have some configuration issue, but I'm pretty close.

I'm having related issues with this.

  • I'm working on a JS project with vscode/typescript checkjs linting.
  • I tried using typings-serviceworker, but it caused all my other non-service-worker files to change scope.
  • I've created a reduced test-case, would be amazing if someone could look at it.

https://github.com/wilsonpage/vscode-scope-test-case

Piecing together several comments in here, this is all I ended up needing:

  • Include webworker lib in tsconfig:
{
    "compilerOptions": {
        "lib": ["dom", "webworker"]
    }
}
  • Redeclare self and export null in service worker file:
export default null;
declare var self: ServiceWorkerGlobalScope;

I found multiple config files and installing npm packages not necessary (or even helpful).

It feels like TypeScript needs to break the various worker types apart in its definitions. This isn't just a service worker issue, it's an issue for other contexts that have a different global, like shared workers & the various worklets.

Either that, or there should be a way to declare which interface is the global.

The various self hacks in this thread only work for references to self. You've still got incorrect types for the global.

self is used in multiple works, so TypeScript may need to specify in the configuration which files refer to which worker types .

Was this page helpful?
0 / 5 - 0 ratings