Skip to content

Respect X-TypeScript-Types header for remote imports #38864

Closed
@danprince

Description

@danprince

Search Terms

  • X-TypeScript-Types
  • Pika CDN / UNPKG
  • Remote types

Suggestion

The TypeScript compiler could respect the X-TypeScript-Types header when pointing to a remote import.

For example:

import * as Redux from "https://cdn.pika.dev/redux";

Right now, the compiler will be unable to resolve the module path and I won't get any type safety, despite the fact that the HTTP response comes with a X-TypeScript-Types header that can be used to find the declarations for that module.

The header has been implemented in Pika in anticipation of Deno (and similar work is being done in UNPKG unpkg/unpkg#243), but I think it would be great if TypeScript itself would download, cache and resolve the declarations too.

Use Cases

Lots of my projects use UNPKG/Pika directly and they're written and shipped in modern JS as ES Modules. I use TypeScript declaration files and the JSDoc syntax extensively to maintain type safety without introducing a source transform step.

If I want type safety for third party modules, I have three options.

  1. Download the module with npm and use paths to alias the remote url to the local declarations
  2. Download the module with npm and use a declaration file to declare module "https://..." { export * from "..." } (this doesn't always work depending on how the module is authored)
  3. Write the types by hand

The options that involve downloading the types through npm also require additional overhead in ensuring that the versions are matching at all times.

Examples

This would be used to write TypeScript without relying on npm. It would also help reduce friction with the Deno community.

Here's a rough sketch of the expected behaviour.

  • The TypeScript compiler sees an import to https://cdn.pika.dev/[email protected]
  • The compiler checks whether the types for that remote url have already been cached (not sure where makes most sense to cache yet, if the url is versioned then it might be possible to cache globally otherwise a project local cache makes more sense).
  • If the device is offline and no cached version is found, then compiler can warn that the types can't be fetched and the import can be treated as any.
  • If the device is online, then it should fetch the url
    • The response includes the X-TypeScript-Types header with a value of /-/[email protected]/dist=es2019,mode=types/index.d.ts
    • The compiler downloads that file and parses it
    • Each referenced module also needs to be downloaded and parsed
    • Once all of the module dependencies are downloaded, add the declarations to the cache.

I would recommend that if implemented, this feature would be locked behind a compiler option. Having the compiler access the network would be an unwelcome surprise if you weren't expecting it.

I also appreciate that putting a networking component into the compiler in the first place might be considered too complex to justify what is an uncommon use case right now, but as support for ES Modules continues to improve and more developers start to use the Deno toolchain, I think we'll see remote imports become far more common. It would be nice if they 'just worked' in TypeScript too.

I also think this could be implemented as a proof of concept in a third party CLI tool as a first step. Eventually I'd prefer to see it as out of the box behaviour in TypeScript itself, but having a fetch-remote-types command that did the same process would be a useful stop-gap. It'd just be frustrating to have to run it whenever an import changed.

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Out of ScopeThis idea sits outside of the TypeScript language design constraintsSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions