Using with a Workers SSR React app
See original GitHub issueHey Cloudflare friends 👋
So I found a bit of a TypeScript problem with SSR React and Cloudflare. Based on workers-types, you shouldn’t include the built-in DOM types on a Workers project which makes sense because workers isn’t a DOM environment. The problem is that some of the code we’re writing runs in the worker and some of it runs in the browser.
So I do need both types available in different parts of my file. Unfortunately AFAIK is not possible with TypeScript. So we need to have both types available for the whole file. Unfortunately, when I include DOM types with @cloudflare/workers-types
, I get a bunch of errors because the types aren’t compatible.
I’m not sure what to do about this. Have y’all faced this before?
Here's what I get when I try to have both DOM and `@cloudflare/workers-types` at the same time:
node_modules/typescript/lib/lib.dom.d.ts:25:1 - error TS6200: Definitions of the following identifiers conflict with those in another file: AbortController, AbortSignal, Blob, BodyInit, Cache, CacheStorage, CloseEvent, Crypto, CryptoKey, DOMException, Event, EventListener, EventListenerOrEventListenerObject, EventTarget, File, FormData, Headers, HeadersInit, MessageEvent, PromiseRejectionEvent, ReadableStream, ReadableStreamDefaultReader, Request, Response, StreamPipeOptions, SubtleCrypto, TextDecoder, TextEncoder, TransformStream, URL, URLSearchParams, WebSocket, WebSocketEventMap, WritableStream, WritableStreamDefaultWriter, caches, console, crypto, self
25 interface AddEventListenerOptions extends EventListenerOptions {
~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:4:1
4 declare class AbortController {
~~~~~~~
Conflicts are in this file.
node_modules/typescript/lib/lib.dom.d.ts:287:5 - error TS2687: All declarations of 'privateKey' must have identical modifiers.
287 privateKey?: CryptoKey;
~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:288:5 - error TS2687: All declarations of 'publicKey' must have identical modifiers.
288 publicKey?: CryptoKey;
~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:650:5 - error TS2687: All declarations of 'kty' must have identical modifiers.
650 kty?: string;
~~~
node_modules/typescript/lib/lib.dom.d.ts:877:5 - error TS2687: All declarations of 'data' must have identical modifiers.
877 data?: T;
~~~~
node_modules/typescript/lib/lib.dom.d.ts:1701:5 - error TS2687: All declarations of 'read' must have identical modifiers.
1701 read?: number;
~~~~
node_modules/typescript/lib/lib.dom.d.ts:1702:5 - error TS2687: All declarations of 'written' must have identical modifiers.
1702 written?: number;
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:3568:11 - error TS2430: Interface 'Comment' incorrectly extends interface 'CharacterData'.
Types of property 'after' are incompatible.
Type '(content: Content, options?: ContentOptions | undefined) => Comment' is not assignable to type '(...nodes: (string | Node)[]) => void'.
Types of parameters 'content' and 'nodes' are incompatible.
Type 'string | Node' is not assignable to type 'Content'.
Type 'Node' is not assignable to type 'Content'.
Type 'Node' is not assignable to type 'string'.
3568 interface Comment extends CharacterData {
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4632:101 - error TS2344: Type 'HTMLElementTagNameMap[K]' does not satisfy the constraint 'Element'.
Type 'HTMLElement | HTMLAnchorElement | HTMLAreaElement | HTMLAudioElement | HTMLBaseElement | ... 63 more ... | HTMLFrameSetElement' is not assignable to type 'Element'.
Type 'HTMLSelectElement' is not assignable to type 'Element'.
Types of property 'remove' are incompatible.
Type '{ (): void; (index: number): void; }' is not assignable to type '() => Element'.
4632 getElementsByTagName<K extends keyof HTMLElementTagNameMap>(qualifiedName: K): HTMLCollectionOf<HTMLElementTagNameMap[K]>;
~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4872:11 - error TS2430: Interface 'Element' incorrectly extends interface 'ChildNode'.
Types of property 'after' are incompatible.
Type '(content: Content, options?: ContentOptions | undefined) => Element' is not assignable to type '(...nodes: (string | Node)[]) => void'.
Types of parameters 'content' and 'nodes' are incompatible.
Type 'string | Node' is not assignable to type 'Content'.
4872 interface Element extends Node, ARIAMixin, Animatable, ChildNode, InnerHTML, NonDocumentTypeChildNode, ParentNode, Slottable {
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4872:11 - error TS2430: Interface 'Element' incorrectly extends interface 'ParentNode'.
Types of property 'append' are incompatible.
Type '(content: Content, options?: ContentOptions | undefined) => Element' is not assignable to type '(...nodes: (string | Node)[]) => void'.
Types of parameters 'content' and 'nodes' are incompatible.
Type 'string | Node' is not assignable to type 'Content'.
4872 interface Element extends Node, ARIAMixin, Animatable, ChildNode, InnerHTML, NonDocumentTypeChildNode, ParentNode, Slottable {
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4922:14 - error TS2687: All declarations of 'tagName' must have identical modifiers.
4922 readonly tagName: string;
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4953:101 - error TS2344: Type 'HTMLElementTagNameMap[K]' does not satisfy the constraint 'Element'.
Type 'HTMLElement | HTMLAnchorElement | HTMLAreaElement | HTMLAudioElement | HTMLBaseElement | ... 63 more ... | HTMLFrameSetElement' is not assignable to type 'Element'.
4953 getElementsByTagName<K extends keyof HTMLElementTagNameMap>(qualifiedName: K): HTMLCollectionOf<HTMLElementTagNameMap[K]>;
~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:8111:11 - error TS2430: Interface 'HTMLSelectElement' incorrectly extends interface 'HTMLElement'.
8111 interface HTMLSelectElement extends HTMLElement {
~~~~~~~~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:14471:11 - error TS2430: Interface 'Text' incorrectly extends interface 'CharacterData'.
Types of property 'after' are incompatible.
Type '(content: Content, options?: ContentOptions | undefined) => Text' is not assignable to type '(...nodes: (string | Node)[]) => void'.
Types of parameters 'content' and 'nodes' are incompatible.
Type 'string | Node' is not assignable to type 'Content'.
14471 interface Text extends CharacterData, Slottable {
~~~~
node_modules/@types/react/index.d.ts:2869:78 - error TS2344: Type 'HTMLSelectElement' does not satisfy the constraint 'HTMLElement'.
The types returned by 'remove()' are incompatible between these types.
Type 'void' is not assignable to type 'Element'.
2869 select: DetailedHTMLFactory<SelectHTMLAttributes<HTMLSelectElement>, HTMLSelectElement>;
~~~~~~~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:4:1 - error TS6200: Definitions of the following identifiers conflict with those in another file: AbortController, AbortSignal, Blob, BodyInit, Cache, CacheStorage, CloseEvent, Crypto, CryptoKey, DOMException, Event, EventListener, EventListenerOrEventListenerObject, EventTarget, File, FormData, Headers, HeadersInit, MessageEvent, PromiseRejectionEvent, ReadableStream, ReadableStreamDefaultReader, Request, Response, StreamPipeOptions, SubtleCrypto, TextDecoder, TextEncoder, TransformStream, URL, URLSearchParams, WebSocket, WebSocketEventMap, WritableStream, WritableStreamDefaultWriter, caches, console, crypto, self
4 declare class AbortController {
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:25:1
25 interface AddEventListenerOptions extends EventListenerOptions {
~~~~~~~~~
Conflicts are in this file.
node_modules/@cloudflare/workers-types/index.d.ts:98:12 - error TS2717: Subsequent property declarations must have the same type. Property 'body' must be of type 'ReadableStream<Uint8Array> | null', but here has type 'ReadableStream<any> | null'.
98 readonly body: ReadableStream | null;
~~~~
node_modules/typescript/lib/lib.dom.d.ts:2444:14
2444 readonly body: ReadableStream<Uint8Array> | null;
~~~~
'body' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:223:3 - error TS2687: All declarations of 'publicKey' must have identical modifiers.
223 publicKey: CryptoKey;
~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:223:3 - error TS2717: Subsequent property declarations must have the same type. Property 'publicKey' must be of type 'CryptoKey | undefined', but here has type 'CryptoKey'.
223 publicKey: CryptoKey;
~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:288:5
288 publicKey?: CryptoKey;
~~~~~~~~~
'publicKey' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:224:3 - error TS2687: All declarations of 'privateKey' must have identical modifiers.
224 privateKey: CryptoKey;
~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:224:3 - error TS2717: Subsequent property declarations must have the same type. Property 'privateKey' must be of type 'CryptoKey | undefined', but here has type 'CryptoKey'.
224 privateKey: CryptoKey;
~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:287:5
287 privateKey?: CryptoKey;
~~~~~~~~~~
'privateKey' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:376:3 - error TS2687: All declarations of 'tagName' must have identical modifiers.
376 tagName: string;
~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:377:12 - error TS2717: Subsequent property declarations must have the same type. Property 'attributes' must be of type 'NamedNodeMap', but here has type 'IterableIterator<string[]>'.
377 readonly attributes: IterableIterator<string[]>;
~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4873:14
4873 readonly attributes: NamedNodeMap;
~~~~~~~~~~
'attributes' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:379:12 - error TS2717: Subsequent property declarations must have the same type. Property 'namespaceURI' must be of type 'string | null', but here has type 'string'.
379 readonly namespaceURI: string;
~~~~~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:4897:14
4897 readonly namespaceURI: string | null;
~~~~~~~~~~~~
'namespaceURI' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:430:84 - error TS2315: Type 'EventListener' is not generic.
430 declare type EventListenerOrEventListenerObject<EventType extends Event = Event> = EventListener<EventType> | EventListenerObject<EventType>;
~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:434:70 - error TS2315: Type 'EventListenerOrEventListenerObject' is not generic.
434 addEventListener<Type extends keyof EventMap>(type: Type, handler: EventListenerOrEventListenerObject<EventMap[Type]>, options?: EventTargetAddEventListenerOptions | boolean): void;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:435:73 - error TS2315: Type 'EventListenerOrEventListenerObject' is not generic.
435 removeEventListener<Type extends keyof EventMap>(type: Type, handler: EventListenerOrEventListenerObject<EventMap[Type]>, options?: EventTargetEventListenerOptions | boolean): void;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:641:3 - error TS2687: All declarations of 'kty' must have identical modifiers.
641 kty: string;
~~~
node_modules/@cloudflare/workers-types/index.d.ts:641:3 - error TS2717: Subsequent property declarations must have the same type. Property 'kty' must be of type 'string | undefined', but here has type 'string'.
641 kty: string;
~~~
node_modules/typescript/lib/lib.dom.d.ts:650:5
650 kty?: string;
~~~
'kty' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:737:3 - error TS2687: All declarations of 'data' must have identical modifiers.
737 data: ArrayBuffer | string;
~~~~
node_modules/@cloudflare/workers-types/index.d.ts:737:3 - error TS2717: Subsequent property declarations must have the same type. Property 'data' must be of type 'T | undefined', but here has type 'string | ArrayBuffer'.
737 data: ArrayBuffer | string;
~~~~
node_modules/typescript/lib/lib.dom.d.ts:877:5
877 data?: T;
~~~~
'data' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:838:3 - error TS2717: Subsequent property declarations must have the same type. Property 'redirect' must be of type 'RequestRedirect | undefined', but here has type 'string | undefined'.
838 redirect?: string;
~~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:1513:5
1513 redirect?: RequestRedirect;
~~~~~~~~
'redirect' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:1183:3 - error TS2687: All declarations of 'read' must have identical modifiers.
1183 read: number;
~~~~
node_modules/@cloudflare/workers-types/index.d.ts:1183:3 - error TS2717: Subsequent property declarations must have the same type. Property 'read' must be of type 'number | undefined', but here has type 'number'.
1183 read: number;
~~~~
node_modules/typescript/lib/lib.dom.d.ts:1701:5
1701 read?: number;
~~~~
'read' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:1184:3 - error TS2687: All declarations of 'written' must have identical modifiers.
1184 written: number;
~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:1184:3 - error TS2717: Subsequent property declarations must have the same type. Property 'written' must be of type 'number | undefined', but here has type 'number'.
1184 written: number;
~~~~~~~
node_modules/typescript/lib/lib.dom.d.ts:1702:5
1702 written?: number;
~~~~~~~
'written' was also declared here.
node_modules/@cloudflare/workers-types/index.d.ts:1238:42 - error TS2508: No base constructor has the specified number of type arguments.
1238 declare abstract class WebSocket extends EventTarget<WebSocketEventMap> {
~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:1248:50 - error TS2508: No base constructor has the specified number of type arguments.
1248 declare abstract class WorkerGlobalScope extends EventTarget<WorkerGlobalScopeEventMap> {
~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:1278:102 - error TS2315: Type 'EventListenerOrEventListenerObject' is not generic.
1278 declare function addEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: EventListenerOrEventListenerObject<WorkerGlobalScopeEventMap[Type]>, options?: EventTargetAddEventListenerOptions | boolean): void;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
node_modules/@cloudflare/workers-types/index.d.ts:1300:105 - error TS2315: Type 'EventListenerOrEventListenerObject' is not generic.
1300 declare function removeEventListener<Type extends keyof WorkerGlobalScopeEventMap>(type: Type, handler: EventListenerOrEventListenerObject<WorkerGlobalScopeEventMap[Type]>, options?: EventTargetEventListenerOptions | boolean): void;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Found 41 errors.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:10
- Comments:11 (5 by maintainers)
Top Results From Across the Web
Rendering React on the Edge with Flareact and Cloudflare ...
Flareact is a new open-source React framework built for Cloudflare Workers. It allows you to render your React apps at the edge rather...
Read more >Improve app performance with React server-side rendering
In this article, I want to introduce you to server-side rending (SSR) with React, reasons to use it, and some popular frameworks for...
Read more >Getting Web Workers right with Browser and Node ( react )
First thing we have to understand, Web Workers are run as independent JS files in the browser, so they are not 'obviously' compatible...
Read more >How to Enable Server-Side Rendering for a React App
In this tutorial, you will initialize a React app using Create React App and then modify the project to enable server-side rendering.
Read more >A hands-on guide for a Server-Side Rendering React app
We have showed how to set up SSR for Create React App. These are the steps: ... We use ReactDOMServer object to render...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Hey friends!
I wanted to recap what’s going on here with some actionable steps people can take today as well as what we should do in the future to resolve this! Let me know if I miss anything or get something wrong.
The Problem: The issue here is that this package has global type definitions for a bunch of web APIs that conflict with the global type definitions for the same APIs provided by the
dom
andwebworker
type package. So if you addworkers-types
anddom
orwebworker
you will get errors about conflicts.What you can do today: The easiest thing you can do today is to remove the
workers-types
package from your Remix (or other) codebase. If you’d still like type safety around Cloudflare specific APIs like KV, you can copy them directly from https://github.com/cloudflare/workers-types/blob/master/index.d.ts or build your own simplified version.What we need to do soon: In lieu of TypeScript changing it’s support in this matter, we should either export a version of this package with only Cloudflare specific types (like @mrbbot mentioned) or change the package from global types to types that need to be imported explicitly (like @petebacondarwin mentions). Either way we’ll need to do some work to get this package to play nice with projects that are already using
dom
andwebworker
.Does that sound right to you all?
I just hit this problem, where I tried to use
hightlight.js
in a worker to generate some HTML that would be used in the browser. But that library explicitly references the DOM library types using/// <reference lib="dom" />
, which causes the same conflicts discussed here.If workers-types cannot be made compatible with the DOM types, which I “think” would solve this, perhaps we should make the workers-types non-global? In other words, we would import them explicitly using something like
import {Response} from '@cloudflare/workers-types
.