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:
- Is this just a failure of the WebStorm type checker to properly recognize that these classes are the same type?
- Is there a way around this? If I could change my module declaration to
declare module Baz
, then I could leavedeclare class MyClass
outside the module and referenceMyEnum
instead asBaz.MyEnum
and everything would resolve correctly. However, the module must be namedfoo:bar/baz
. Is there a way I can dereference this module to the exportedMyEnum
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.