1

My Javascript is running inside V8, which has a module foo:bar/baz available for import which is resolved by C++. I'm trying to write Typescript definitions for this module, so clients can interface with it in a type safe manner.

Here is the actual specification that I'm describing (in pseudo-code):

module 'foo:bar/baz' {
    ENUM1 // A magic object of unique but unknown value.
    ENUM2 // Same
    ENUM3 // Same
    doSomething(): MyClass
    // where MyClass has a member function that returns one of the above enums.
}

My goal is to provide type declarations for this module without exposing additional types or functionality that do not exist in the module.

Here is my declaration file:

declare module 'foo:bar/baz' {
    export const ENUM1: unique symbol;
    export const ENUM2: unique symbol;
    export const ENUM3: unique symbol;

    // Unexported because there is no MyEnum in the true module.
    export type MyEnum = typeof ENUM1 | typeof ENUM2 | typeof ENUM3;
    export function doSomething(): MyClass;
}

declare interface MyClass {
    member(): MyEnum;
}

And my usage of this module is:

import * as baz from 'foo:bar/baz';

/** @type MyClass */
const x = baz.doSomething();

The issue right now is that MyEnum is not available in the scope of declare class MyClass as it lives in the foo:bar/baz module. I've tried adding import { MyEnum } from 'foo:bar/baz' between the module and class declarations, but my linter says that module cannot be found.

If I change the declaration to be:

declare module 'foo:bar/baz' {
    export const ENUM1: unique symbol;
    export const ENUM2: unique symbol;
    export const ENUM3: unique symbol;

    export type MyEnum = typeof ENUM1 | typeof ENUM2 | typeof ENUM3;
    export function doSomething(): MyClass;

    interface MyClass {
        member(): MyEnum;
    }
}

Then MyEnum does resolve in the scope of MyClass, however, now my type checker does not recognize any methods on x, as there is no MyClass in the scope of my usage, only baz.MyClass.

If I change my annotation to @type baz.MyClass, then the type checker does show methods on x however now the assignment is invalid with the error Initializer type MyClass is not assignable to variable type baz.MyClass.

Two questions here:

  1. Is this just a failure of the WebStorm type checker to properly recognize that these classes are the same type?
  2. Is there a way around this? If I could change my module declaration to declare module Baz, then I could leave declare class MyClass outside the module and reference MyEnum instead as Baz.MyEnum and everything would resolve correctly. However, the module must be named foo:bar/baz. Is there a way I can dereference this module to the exported MyEnum member?

The only workaround I've been able to find is to use the second declaration mentioned and change my usage to:

import * as baz from 'foo:bar/baz';
import { MyClass } from 'foo:bar/baz';


/** @type MyClass */
const x = baz.doSomething();

This yields proper type resolution of x without a type error on the assignment. However, foo:bar/baz does not have a MyClass, as mentioned at the beginning, so my understanding is that this import would fail to resolve.

jmrk
  • 34,271
  • 7
  • 59
  • 74
DontTurnAround
  • 684
  • 1
  • 7
  • 20
  • I don't see a reason why `MyClass` should not be part of the module. It's not a global. Yes, it needs to be an `interface` or `type` declaration, not a `class` declaration. I think your third snippet where you declare the `interface MyClass` inside the module should work, you only forgot to `export` the interface in there. – Bergi Jun 30 '20 at 20:41
  • @Bergi If I do as you suggest, then I get an error from my linter `Initializer type MyClass is not assignable to variable type baz.MyClass` hence my question (1). – DontTurnAround Jun 30 '20 at 20:49
  • Hm, might this be [a Webstorm bug](https://stackoverflow.com/q/54238584/1048572)? – Bergi Jun 30 '20 at 20:59
  • Seems likely, given that those two classes should be the same class. However, I'm running build `WS-192.7142.35` while that post claims the issue is fixed in `>=WS-191.3749` – DontTurnAround Jun 30 '20 at 21:29

0 Answers0