-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot use class as type if nested into object or class #46938
Comments
I don't see a bug here. The correct syntax for what you want is:
This is all working as intended. |
Writing I will try to give a bit more insight why I consider it as a misbehavior and what my actual workflow is. Hopefully this changes our discussion in a way that will allow me filing the right kind of issue with the right details π This is the setup and files I get from the individual steps in my compilation chain: // Test.ts
export class Test { }
// MyLib.ts (and MyLib.js after TS compilation)
import { Test } from './test';
export const Const = {
Test: Test
}
// MyLib.js after rollup (UMD)
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.myLib = {}));
}(this, (function (exports) { 'use strict';
class Test {}
const Const = {
Test
};
exports.Const= Const;
Object.defineProperty(exports, '__esModule', { value: true });
})));
// MyLib.mjd after rollup (ESM)
class Test {}
const Const = {
Test
};
export { Const }
// MyLib.d.ts
declare class Test { }
declare const Const {
Test: typeof Test
}
export { Const }; This output leads to the reported issue where import { Const } from 'myLib';
const a: Const.Test = new Const.Test(); // error on the type annotation, fine on the constructor There is a workaround to this "problem" I am currently evaluating. This structure rather builds on top of the module concepts. It will ultimately result in namespaces in the // Const.ts
export { Test } from './Test'
// MyLib.ts and MyLib.js after TS and before Rollup
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.myLib = {}));
})(this, (function (exports) { 'use strict';
export * as Const from './Const.ts'
// MyLib.js (after rollup)
class Test { }
var index$1 = Object.freeze({
__proto__: null,
Test: Test
});
exports.Const = index$1;
Object.defineProperty(exports, '__esModule', { value: true });
}));
// MyLib.mjs
class Test {}
var index$1 = Object.freeze({
__proto__: null,
Test: Test
});
export { index$1 as Const };
// MyLib.d.ts (through Rollup)
declare class Test { }
type index_d$1_Test = Test;
declare const index_d$1_Test: typeof Test;
declare namespace index_d$1 {
export {
index_d$1_Test as Test,
};
}
export { index_d$1 as Const }; As you can see the actual JS output is structurally the quite same to the other variant. But the big difference lies in the As indicated in #4529 putting exports into a namespace (like in the generated Maybe we could say it's a bug (or missing feature if you prefer π ) that we have TS1194 with the following input (?): // close to the structure above
namespace Const {
export { Test } from './test';
}
export { Const };
// or even shorter
export namespace Const {
export { Test } from './test';
} My workaround to define my namespaces/scopes as modules and use the re-exporting of modules seems to give me the output I like. So I could live with this. It feels inconvenient that I cannot do the same thing with keeping all library exports within one file requiring me to split it up. What's your opinion on this use case? |
The syntax you're requesting to do something already has a different meaning: const Const = {
Test2: class {
m = 10;
}
}
namespace Const {
export interface Test2 {
m: string;
}
}
const m: Const.Test2 = { m: "hello" } |
This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes. |
Bug Report
π Search Terms
nested class type object
π Version & Regression Information
Type System Behavior
β― Playground Link
Playground link with relevant code
π» Code
π Actual behavior
TypeScript does not allow to use the nested types within objects or classes as part of type annotations. It complains with errors like
Cannot find namespace 'Const'.ts(2503)
as TypeScript only seem to allow referencing nested types only if they are nested using namespacesπ Expected behavior
We should be able to use also classes/types aliased through objects or nested classes as type annotations in variables, return types etc.
Use Case
This topic relates a bit to #4529
I am bundling up my library into an all-in-one module (using Rollup) containing one entry point to my library while I want to keep a bit of a module-alike organization of my classes through this nesting approach. Considering all the current restrictions regarding exports and namespaces going for nesting is currently the "best" approach with keeping 1 file for your library.
Consumers of my library can access all the classes to create instances but they cannot use my types in their codebases to annotate their variables and functions.
My library is available in a wide variety of environments supporting module (ESM, UMD) and non-module (classical browser script include) usages.
The text was updated successfully, but these errors were encountered: