Description
Problem
In Deno we have // @deno-types
pragmas to provide the "types resolution" for a module specifier. For example:
// @deno-types="https://example.com/example.d.ts"
import * as example from "https://example.com/example.js";
At runtime this resolves to https://example.com/example.js
and when type checking it resolves to https://example.com/example.d.ts
.
There's a few problems with this:
- It's Deno specific.
- It doesn't work with dynamic imports.
- It's using line comments to determine module resolution.
- There's no syntax errors when making a mistake writing it.
- It's kind of hard to remember.
- It differs from Deno's other comment pragmas (Cambrian explosion of comment pragmas #11334).
Proposal: Move specifier to import attribute
Although the // @deno-types
pragma has served us well, we now have import attributes, which would be a better place to store this information. For example:
import express from "npm:express" with {
types: "npm:@types/express",
};
// or with a dynamic import
const express = await import("npm:express", { with: { types: "npm:@types/express" }});
Key name
Probably a types
key is best because it aligns with terminology elsewhere (ex. in a package.json). An issue with types
as a potential key name is that the type
import attribute key exists (ex. "type": "json"
). I think this is not a big deal and the two will appear distinct enough based on their value and any issues will be pointed out through errors. For precedence, package.json files also both have "type"
and "types"
keys. Additionally, the two will probably rarely ever appear side by side.
Other considerations for the key were dts
and declaration
, but and issue with these is that it's not just declaration files that could be referenced here.
Transpiled away or left at runtime?
Probably it should be left at runtime. This will enable its use in JavaScript files. An issue is that the runtime would need to be changed to not throw for this key, but I believe it's host defined so we can allow that.
Why do we need this in the first place? Why doesn't this just go in a config file?
First class support for scripts without a config file is very important. It enables scenarios like using these imports in jupyter notebooks without config files as well as the repl. This also enables scenarios where you can distribute code as code instead of code with a config file.
Related issues: