Need to export classes for NPM package - node.js

I am building an NPM package and am looking for the best way to export my classes.
Right now, I am using this:
import {Swan} from './Swan';
import {Route, Router} from './Router';
import {View, TemplateView, IView} from './views';
export { Route, Router, Swan, View, TemplateView, IView };
This works. The only thing is, of course, each time I add a new class, I have to update the export statement.
Is there a way to export all the classes in all the files I specify without having to update the export statement here?

Is there a way to export all the classes in all the files I specify without having to update the export statement here?
There is no automatic "export everything" or export all classes in Javascript.
But, you could change how you define your classes so they are part of an internal object and you just export that object.
const myExports = {
TemplateView: class TemplateView {
...
},
iView: class iView {
...
}
};
export default myExports;
When you add a new class to this structure, it automatically becomes part of the exports.
On the other hand, I personally don't see what the big deal is to maintain the export list when you add a new item to the module that you want exported. Exports are SUPPOSED to be a thoughtful list of things that only contains the items that need to be exported and does not contain other functions used locally as part of the implementation. The only way that it can be a thoughtful list is if it's not automatic.

Related

How to do lazy export in Typescript

Module: shared-module
export * from "./common-types";
export * from "./lots-of-large-classes"
Let's say I have 200 large classes and import the above module like
Module: Main
import { CommonTypeClass } from "shared-module"
Now all 200 classes "also" will load as they are resolved in static scope and referred in my import.
To avoid this I tried
Object.defineProperty(module.exports, 'lots-of-large-classes', {
// The lots-of-large-classes folder is very large. To avoid pulling it in from static
// scope, we lazy-load the module.
get: () => require('./lots-of-large-classes'),
});
But VS Code isn't showing the lots-of-large-classes import.
import { LargeClassOne } from 'shared-module/lots-of-large-classes'; // ISN'T WORKING
However, above solution also still loads all classes as there is an index file which loads all classes.
How can I selective load LargeClassOne from lots-of-large-classes folder without loading other classes through shared-module?
Something like with overhead of loading one large class alone which is being imported.
import { LargeClassOne } from 'shared-module/lots-of-large-classes';
It's not possible to statically import dynamically-loaded data. Using subpath exports in the package.json for "shared-module" will help you accomplish your goal.
You can combine this with TypeScript's path mapping feature for very flexible import specifiers.

How to allow CommonJS programs to import from my TypeScript library without using require().default and having autocomplete in text editors

I'm currently developing a TypeScript library to be used internally in my company's projects, which are a mix of JavaScript and TypeScript Node applications.
So, I want to be able to import the library's default class properly in JavaScript with CommonJS. However, I can only use my class in these programs if I import it with require('...').default.
I managed to make it work previously by adding a module.exports = MyClass at the end of the file, but the autocomplete of VSCode doesn't seem to catch up to that, still suggesting the default before showing the methods.
How can I make it so I can import my class by just using require('...') while still making sure the autocomplete is properly working?
Thanks.
EDIT:
For clarity, what I want to do is to be able to do this:
const MyClass = require('MyTypeScriptClass');
instead of:
const MyClass = require('MyTypeScriptClass').default;
Edit
I decided to not use export default when exporting from a library, since it seems to be what every other library does.
The TypeScript equivalent should be this:
class MyClass {
}
export = MyClass
Can also be inlined to export = class MyClass { ... if that is preferred.
(To import an export like this in a TypeScript project you need to set the esModuleInterop flag.)

Prevent an es6 default export from being imported

I have a small node package that I would like users to only used named imports in their project.
import { Logger } from 'logger';
However, there is nothing stopping the user from doing
import defaultImportedLogger from 'logger';
They will just learn the hard way when they find out that defaultImportedLogger is undefined because my project doesn't have an export default anywhere. Hence the default export is undefined.
If I try to import a named exports such as:
import { foo } from 'logger'
my editor will complain because foo isn't exposed. Why doesn't my editor complain in the default import situation?
The result of trying to import the default export when it wasn't defined depends on which bundler you're using. For example Rollup throws an error: "'default' is not exported by <filename>".
I don't think there's any way to prevent users from importing the default export. The best you can do is export a function which throws an error when called, with error message "Don't use the default export".

Using TypeScript Declaration For External JavaScript Library

I'm not sure if this extreme edge case or something but I cannot seem to find straight forward documentation on how to do this (or I'm just really not understanding what is available):
I am developing an ionic application and as part of that I need to use the ALKMaps JavaScript library (which is similar to Google Maps API). To do so, I created a local npm module and within that I created a alkmaps.d.ts file as recommended by https://www.typescriptlang.org/docs/handbook/declaration-files/by-example.html#objects-with-properties). However, I cannot seem to figure out how to properly import it into my angular code. The same document suggests that using <reference path=''> tags is not good but that is the only thing that seems to satisfy the tsc compiler.
My declaration file, alkmaps.d.ts, looks like (inside excluded for brevity):
declare namespace ALKMaps {
export class Map { ... }
...
}
And I was trying to import it into a file like:
import { ALKMaps } from 'alkmaps'; // Error: File '.../alkmaps.d.ts' is not a module
I also tried the following but got the same error.
import ALKMaps = require('alkmaps');
Using the reference tag seems to work within this module but then the project that utilizes this module still throws the "is not a module" error (that might warrant a separate question)
From https://github.com/Microsoft/TypeScript/issues/11420 I found the idea of using export = ALKMaps or export as namespace ALKMaps but adding those to my declaration file resulted in different errors instead.
Can anyone please explain in a straightforward way how to use declaration files representing external JS libraries in a typescript node module?
This is how I was able to get alkMaps into my Angular 2 app
Insert the script into the index.html file.
Declare an ALKMaps variable in the component that you are adding the map
imports .....
declare let ALKMaps : any;
#Component({
selector: 'show-map',
templateUrl: 'show-map.component.html'
})
export class ShowMapComponent implements Oninit{
map : any;
constructor() {
}
ngOnInit() {
ALKMaps.APIKey = "apiKey";
this.map = new ALKMaps.Map("map", {displayProjection: new ALKMaps.Projection("EPSG:4326")});
}
}
This will get the map to display and you can put different layers on the map, however the map does not display correctly. #Mike, if you were able to get further than this, will you please comment?
EDIT: The tiles on the image were elongated and not connected. After inspecting the css the main.css, after building, set a global property on the img element to:
img {
max-width:100%
}
The tiles for the map are originally set to 256% for the width. To correct the element, I changed the property for img in the style sheet.
show-map {
img {
max-width: 256%
}
}

Develop/Organize a node module in TypeScript

I want to develop a node module in TypeScript, but I'm having some problems with all the possible options to require, import, etc.
What I'm doing right now is having every class and interface in it's own file. So I would need to require all the dependencies which is kind of stupid, because I'm typing the class name twice, like this:
import Target = require('./Target');
export interface IFace {
getTarget(): Target.Target
}
I could write import t = require('./Target'); instead but then I need to write t.Target which I think is also pretty ugly.
And also I can't give it a module name (like FaceApp), because when I need to import two files, there's a naming conflict.
Obviously that would not be needed if everything would live in one file, but this is far from optimal I think.
So how do you guys organize your node module in TypeScript? I'd be happy to hear your suggestions.
You can avoid the name duplication by using the export = syntax. i.e. Do:
class Target{}
export = Target;
instead of export class Target.
Also grunt-ts transformers can help you with the import statement explosion : https://github.com/grunt-ts/grunt-ts/issues/85#issue-29515541
The way recommended by TypeScript is to do
export default class Target {}
and then you can do a true typescript import with
import Target from './Target'
alternatively, you can rename it
import NewName from './Target'
Also note that you can export multiple things from a file if they are related
export class SomeClass {}
export class OtherClass {}
And that on import, you can change the names
import { SomeClass as MySomeClass, OtherClass as MyOtherClass } from './Target'

Resources