question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

RFC: Exportable types

See original GitHub issue

One request we’ve had is to provide user importable types from this package—i.e. a way to use worker types without declaring it in tsconfig.json. This is easy enough for most of our types (ExecutionContext, for instance):

// types.d.ts
export interface ExecutionContext {
  waitUntil(promise: Promise<any>): void;
  passThroughOnException(): void;
}
// index.ts
import { ExecutionContext } from "./types.d.ts"

The rest of this issues will address options for providing importable types for globals like Response, Request, and fetch, which are both values and types.

Is this a problem to solve?

The workers runtime does have the globals Response etc…, and so in some sense using ambient declarations is the “right” approach (as this package does currently). However, there are downsides, including the lack of automatic inclusion of @types/* packages, and the fact that workers can’t be typed correctly in frameworks like Remix, which mix browser code and worker code in the same project (and even file!).

Here’s a very simple example of a Remix file that doesn’t typecheck, because Response.json() is non standard. It runs fine when published, as Response.json() is available in the workers runtime.

import { useLoaderData } from '@remix-run/react';

export const loader = async () => {
  return Response.json({
    data: [
      {
        slug: 'my-first-post',
        title: 'My First Post'
      }
    ]
  });
};
export default function Index() {
  const { data } = useLoaderData();
  return <div>{JSON.stringify(data)}</div>;
}

How about just…exporting the types?

At first glance, just adding an export keyword would seem to solve the issue:

// types.d.ts
export declare class Response extends Body {
   ...
}
// index.ts
import { Response } from "./types.d.ts"

Indeed, this typechecks fine, but doesn’t build fine (esbuild can’t find the Response export).

An honestly pretty reasonable option for classes

// types.d.ts
declare class Response extends Body {
  ...
}
class WorkerResponse extends Response {}

export {WorkerResponse as Response}
// index.ts
import { Response } from "./types.d.ts"

This both typechecks and builds with esbuild, as well as (as far as I can tell) working completely fine in the runtime.

It also provides a solution for the Remix example given earlier:

```ts
import { useLoaderData } from '@remix-run/react';
import { Response as WorkerResponse } from './types.d.ts';

export const loader = async () => {
  return WorkerResponse.json({
    data: [
      {
        slug: 'my-first-post',
        title: 'My First Post'
      }
    ]
  });
};
export default function Index() {
  const { data } = useLoaderData();
  return <div>{JSON.stringify(data)}</div>;
}

Frankenstein’s monster

One type remains; the function:

declare function fetch(
  request: Request | string,
  requestInitr?: RequestInit | Request
): Promise<Response>;

I propose the following solution:

// types.d.ts
declare function fetch(
  request: Request | string,
  requestInitr?: RequestInit | Request
): Promise<Response>;

// @ts-ignore next-line
const WorkerFetch: typeof fetch = globalThis.fetch

export {
  WorkerFetch as fetch
}

// @ts-ignore next-line is needed because globalThis isn’t typed. Can we type globalThis, you may ask? No, since that would inject fetch as a global type, which is exactly what this approach is trying to avoid.

This typechecks, builds, and runs correctly, but is a bit…horrifying. If anyone has any suggestions on how to improve this I’m all ears!

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:2
  • Comments:6 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
penalosacommented, Oct 17, 2022

@GregBrimble

  1. No, because a class is both a type and a value, whereas const Response = globalThis.Response is just a value. To get the type of Response, you’d need to use typeof Response, which breaks the usual expectation for classes. That’s an okay tradeoff for functions, because you need typeof for functions anyway (I’m pretty sure, at least).
  2. Yes, this would be just another option
Read more comments on GitHub >

github_iconTop Results From Across the Web

RFC 7013 - Guidelines for Authors and Reviewers of IP ...
Guidelines for Authors and Reviewers of IP Flow Information Export (IPFIX) Information Elements (RFC 7013, September 2013)
Read more >
Export and Import RFCs for a system refresh
For Export RFC destinations, fallow the below steps. Create a Transport of copies type request on QA system which is going to be...
Read more >
Information on RFC 4757
RFC 4757. The RC4-HMAC Kerberos Encryption Types Used by Microsoft Windows, ... and provide exportable (meet United States government export restriction ...
Read more >
Export type definitions · Issue #195 · cloudflare/workers-types
Would it be possible to export the type definitions in index.d.ts? That would make it possible to use the types in JavaScript projects....
Read more >
How to Export RFC in SAP System and From OS Level
Video Explains on how to take RFC Export in SAP system using Transport of copies and Also using R3trans in OS level.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found