TypeScript Version: 3.5.2
Search Terms: ambient module declaration export declare class type name
Code
In a file called classes.d.ts:
declare class A {}
export declare class B extends A {}
In a file called test.js:
let a = require('classes').A;
In a file called test.ts:
import { A } from './types/classes';
_[NEW]_ Assumptions:
The following is a list of assumptions I had when originally opening this issue:
import or export [on a top-level declaration], only explicitly exported declarations are visible externally.import types (at least those that are _used_ by exported types.export class B extends A exports the type names A and B, even if A was not directly exported.#1 above) are only accessible if explicitly exported.These assumptions are the result of reading the documentation and working with declaration files. Note that the documentation _does not_ mention:
export {}; syntax causes only explicitly exported declarations to be available by consumers of the declaration file.I list them here to provide context for the Expected Behavior section.
Expected behavior:
In both cases , an Error that name 'A' could be found in module 'classes'.
I expect in this case that TypeScript is capable of resolving the following from the declaration file:
In other words, I should be able to use import types to resolve class A, but attempts to _use_ them should fail.
Actual behavior:
No compiler error in either case. TypeScript-powered IDEs (e.g. VSCode) happily show that the _full_ non-exported class A is available.
In short, a non-exported, declared class should resolve in the same way as an interface.
As things stand today, TypeScript erroneously resolves the Value "A".
Playground Link: NA
Related Issues: NA
Without support for this it is extremely difficult to model a module that has a private base class with many public subclasses.
The following is a snippet of JavaScript:
// ↓ OK!
/** @type {import('classes').A} */
let x;
// ↓ ERROR!
let y = x instanceof require("classes").A;
The import type currently works as expected. 👍
The instanceof line beneath it does _not_ report the expected error. 👎
In a declaration file everything is implicitly exported. You can prevent that by adding export{};.
With that change you can also no longer use A as type. To fix that you need to export it as interface.
In a declaration file everything is implicitly exported.
Is that documented anywhere? That should _really_ be documented.
You can prevent that by adding
export{};.
This should also be documented. Does this syntax have a name?
With that change you can also no longer use
Aas type. To fix that you need to export it as interface.
@ajafff What do you mean that you can "export it as interface"?
I see three options:
A class to AClass and export a type: export type A = AClass;.A class to AClass and export an interface: export interface A extends AClass {}.Here are the issues with those options:
class, the type shown on _hover_ reads as the resolved AClass. Which is _not_ the desirable information to convey.interface rather than a class.In my opinion, the third option is the best of the bunch.
Is there really no way to [meaning-full-y] export the type of a class rather than both its type _and_ value?
Most helpful comment
Is that documented anywhere? That should _really_ be documented.
This should also be documented. Does this syntax have a name?
@ajafff What do you mean that you can "export it as interface"?
I see three options:
Aclass toAClassand export a type:export type A = AClass;.Aclass toAClassand export an interface:export interface A extends AClass {}.Here are the issues with those options:
class, the type shown on _hover_ reads as the resolvedAClass. Which is _not_ the desirable information to convey.interfacerather than aclass.In my opinion, the third option is the best of the bunch.
Is there really no way to [meaning-full-y] export the
typeof a class rather than both itstype_and_value?