Deno: Pulling typedefs for remote js packages

Created on 22 Nov 2020  Â·  2Comments  Â·  Source: denoland/deno

I'm trying to use a library that's distributed as js with .d.ts files and struggling to correctly pull in the typedefs. I'm wondering if there's a step I'm missing or config needed to make this work.

The specific library I'm using is xstate but this applies to many packages in the node ecosystem that could theoretically work with Deno.

Here's an example of using the library.

// # import_map.json
{
  "imports": {
    "https://unpkg.com/[email protected]/es/environment.js": "./xstate.environment.ts"
  }
}

// # xstate.environment.ts
// needed b/c this file uses node-specific APIs not available in deno
export const IS_PRODUCTION = Deno.env.get('IS_PRODUCTION');

// # app.ts
// @deno-types="https://unpkg.com/[email protected]/es/index.d.ts"
import { Machine } from 'https://unpkg.com/[email protected]/es/index.js';

function doSomethingWithAMachine(machine: Machine) {
  machine.send({});
}

I would expect this to be able to compile, but this happens:

➜ deno run --unstable --allow-env --import-map ./import_map.json app.ts       
Check file:///home/bkamm/git/poop-smoothy/app.ts
error: TS2305 [ERROR]: Module '"https://unpkg.com/[email protected]/es/Actor.js"' has no exported member 'Actor'.
import { Actor } from './Actor';
         ~~~~~
    at https://unpkg.com/[email protected]/es/index.d.ts:6:10

TS7034 [ERROR]: Variable 'InterpreterStatus' implicitly has type 'any' in some locations where its type cannot be determined.
import { interpret, Interpreter, spawn, InterpreterStatus } from './interpreter';
                                        ~~~~~~~~~~~~~~~~~
    at https://unpkg.com/[email protected]/es/index.d.ts:8:41

TS2694 [ERROR]: Namespace '"https://unpkg.com/[email protected]/es/types.js"' has no exported member 'CancelAction'.
    cancel: (sendId: string | number) => import("./types").CancelAction;
                                                           ~~~~~~~~~~~~
    at https://unpkg.com/[email protected]/es/index.d.ts:16:60

TS2694 [ERROR]: Namespace '"https://unpkg.com/[email protected]/es/types.js"' has no exported member 'EventObject'.
    at https://unpkg.com/[email protected]/es/index.d.ts:19:57

TS2694 [ERROR]: Namespace '"https://unpkg.com/[email protected]/es/types.js"' has no exported member 'EventObject'.
    at https://unpkg.com/[email protected]/es/index.d.ts:19:89

TS2694 [ERROR]: Namespace '"https://unpkg.com/[email protected]/es/types.js"' has no exported member 'Assigner'.
    at https://unpkg.com/[email protected]/es/index.d.ts:19:132

TS2694 [ERROR]: Namespace '"https://unpkg.com/[email protected]/es/types.js"' has no exported member 'PropertyAssigner'.
    at https://unpkg.com/[email protected]/es/index.d.ts:19:179

TS2694 [ERROR]: Namespace '"https://unpkg.com/[email protected]/es/types.js"' has no exported member 'AssignAction'.
    at https://unpkg.com/[email protected]/es/index.d.ts:19:236

TS7005 [ERROR]: Variable 'InterpreterStatus' implicitly has an 'any' type.
    at https://unpkg.com/[email protected]/es/index.d.ts:28:150

TS2749 [ERROR]: 'Machine' refers to a value, but is being used as a type here. Did you mean 'typeof Machine'?
function doSomethingWithAMachine(machine: Machine) {
                                          ~~~~~~~
    at file:///home/bkamm/git/poop-smoothy/app.ts:4:43

Found 10 errors.

This isn't working because index.d.ts is reexporting types from other files - but Deno is resolving the relative exports to the underlying js files which are missing type information. To get this work I keep adding additional deno-types directives, like this:

// @deno-types="https://unpkg.com/[email protected]/es/index.d.ts"
// @deno-types="https://unpkg.com/[email protected]/es/Machine.d.ts"
// @deno-types="https://unpkg.com/[email protected]/es/State.d.ts"
// @deno-types="https://unpkg.com/[email protected]/es/StateNode.d.ts"
// @deno-types="https://unpkg.com/[email protected]/es/StateNode.d.ts"
// @deno-types="https://unpkg.com/[email protected]/es/types.d.ts"
// @deno-types="https://unpkg.com/[email protected]/es/interpreter.d.ts"
// ETC...
import { Machine } from 'https://unpkg.com/[email protected]/es/index.js';

function doSomethingWithAMachine(machine: Machine) {
  machine.send({});
}

But (1) it doesn't seem like Deno is successfully matching typedefs to their related js files, and (2) this is very inconvenient and breaks encapsulation, because instead of relying on the public API published by the package, I need to dig in the specific file layout and import all of the various files. and (3) I end up needing to do this in every file where I want to consume xstate, or to make a local xstate.ts file which simply imports the library and all typedefs and then reexports everything. Which is again kind of tedious to use a library.

Is there a way to get Deno to recognize or find the .d.ts files alongside all of the published js files for a package like this?

question

All 2 comments

@boxfoot This works

import {
  send,
  Machine
} from "https://cdn.skypack.dev/xstate?dts";

Don't expect d.ts files to work as they are (unpkg distributes them without transformations), most of them need some kind of transformation in order to work properly in Deno. Sometimes this is due to the need of these files to use ES modules (with extension), and sometimes due to the "strict" nature of Deno's TypeScript.

@Soremwar thanks for the tip to check out skypack.dev. It's working perfectly (although I recognize types may not always) and as an extra bonus, the skypack build removed the process.env dependency on its own so I don't need to do that manually.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

benjamingr picture benjamingr  Â·  3Comments

kyeotic picture kyeotic  Â·  3Comments

davidbarratt picture davidbarratt  Â·  3Comments

justjavac picture justjavac  Â·  3Comments

JosephAkayesi picture JosephAkayesi  Â·  3Comments