TypeScript Node.js package - node.js

I am making a node.js package found here
Development is going well, all except one thing. All of my code is in one file, index.ts.
I googled with no luck on how to separate the classes into different files and then be able to put them all together as a package in the end, while keeping the typescript types and all.
There are many ways to do it, but then they break IntelliSense (the items do not show up). Due to the whole reason I am using typescript is to have IntelliSense, and somewhat inline documentation, that is not a viable option.
Any help would be appreciated.
SOLUTION:
./Help/HelpModule.ts
export enum HelpMode {
/**
* Disable the automatic help command.
*/
Disabled,
/**
* Use the automatic help command and respond in the channel the command is used.
*/
Public,
/**
* Use the automatic help command and respond in a private message.
*/
Private
}
./index.ts
export * from './Help/HelpMode';

To split out your code into multiple files you must first move your functions into a new file, export them, then import them into your new file.
For example
//index.ts
function fooA() { .. }
function fooB() { .. }
If we want to split foo B into its own file. We do:
//index.ts
import { fooB } from "./fooB";
function fooA() { .. }
And the other file would be
//fooB.ts
export function fooB() { .. }

Related

Put data on ServersideProps

Is it possible to get data from server side's config file on client by getServersideProps() in Next.js? How to put data in props? Or how to get it on client in other way?
I have tried publicRuntimeConfig in next.config.js, but it is undefined and I don't know why...
It's hard to tell exactly what's going on but I have one idea from experience: You need to make sure you're calling nextJSApp.prepare() before any modules using next/config are included.
As an example,
// SomeComponent.tsx
import { getConfig } from 'next/config'
const config = getConfig()
export interface X { ... }
// server.ts
import { X } from './SomeComponent'
app.prepare().then(...)
This fails because module are loaded first and the config hasn't been initialized until app.prepare has been completed.
The solution for this is to either use TypeScript's import(...) syntax if you just need a type or use node's require for dynamic resolution during runtime.

Need to export classes for NPM package

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.

Can't import exported functions

I am having strange issues with Typescript when I import things from a file which exports them. Sometimes I will export a function, then import it to another file, then I use the function and it is not a function anymore. When I define the function in the same file, all of a sudden the function is a function?!?!?
Why would a function stop being a function when it is exported? I have had similar problems with classes too.
The hard part of this issue is I can't recreate a simple example because it only happens when I am using some kind of higher level package.
For example, I had a similar issue with sequelize-typescript here: my github issue with typescript-sequelize
Below is some codes showing off the basic issue I'm having with one of the decorators from InversifyJS.
container.ts
import {fluentProvide} from "inversify-binding-decorators";
export const provideSingleton = (identifier: any) => {
return fluentProvide(identifier)
.inSingletonScope()
.done(true);
};
test.service.ts
import {provideSingleton} from './container'
#provideSingleton(TYPES.TEST)
export default class TestService {}
The strangest thing is when I put the provideSingleton in the same file as the TestService, everything works!?!?!
Basically to recreate the issue, simply follow the example from here: inversify-binding-decorators - Using #provideFluent multiple times. However there is an issue with the example, so please see this issue: fluentProvide example needed. The above provideSingleton reflects the changes from that issue. Then you simply import the provideSingleton function from another file instead of defining it in the same like in the example.
Can anyone explain to me what I'm missing? Why oh why would certain exported items not bee seen as the type they are? Is there a step I'm not seeing that NodeJS takes to make the item actually exported and therefore different? Can I force the function to resolve as a function so it can be used as such?
ENV:
NodeJS: 10.9.0
Typescript: 3.0.1
Mac: 10.13.16
So it looks like you can get issues like this when NodeJS can't handle a recursive import. I'm not exactly sure how to check you are getting this error other than your symptoms are like what I stated above. Basically the recursion caused my function to not load and therefore undefined is not a function.
It would be easy to notice if you had code like so:
a.ts
import B from './b';
export default class A extends B {}
b.ts
import A from './a';
export default class B extends A {}
In my case, I think my function provideSingleton did not like the file I put it in because of some conflicting code in the file, which all I had was:
import {Container} from 'inversify';
import "reflect-metadata";
import {fluentProvide} from "inversify-binding-decorators";
const container = new Container();
function ProvideSingleton(identifier: any) {
return fluentProvide(identifier)
.inSingletonScope()
.done(true);
}
export {container, ProvideSingleton}
In the end, if this issue comes up, try another file for your function and pay good attention to how the order of the loading happens. Although NodeJS handles recursive imports most of the time, you can still trip it out.

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%
}
}

Writing ENV variables to configure an npm module

I currently have a project in a loose ES6 module format and my database connection is hard coded. I am wanting to turn this into an npm module and am now facing the issue of how to best allow the end user to configure the code. My first attempt was to rewrite it as classes to be instantiated but it is making the use of the code more convoluted than before so am looking at alternatives. I am exploring my configuration options. It looks like writing to the process env would be the way but I am pondering potential issues, no-nos and other options I have not considered.
Is having the user write config to process env an acceptable method of configuring an npm module? It's a bit like a global write so am dealing with namespace considerations for one. I have also considered using package.json but that's not going to work for things like credentials. Likewise using an rc file is cumbersome. I have not found any docs on the proper methodology if any.
process.env['MY_COOL_MODULE_DB'] = ...
There are basically 5ish options as I see it:
hardcode - not an option
create a configured scope such as classes - what I have now and bleh
use a config such as node-config - not really a user friendly option for npm
store as globals/env. As suggested in comment I can wrap that process in an exported function and thereby ensure that I have a complex non collisive namespace while abstracting that from end user
Ask user to create some .rc file - I would if I was big time like AWS but not in this case.
I mention this npm use case but this really applies to the general challenge of configuring code that is exported as functions. I have use cases for classes but when the only need is creating a configured scope at the expense (in my case) of more complex code I am not sure its worth it.
Update I realize this is a bit of a discussion question but it's helped me wrap my brain around options. I think something like this:
// options.js
let options = {}
export function setOptions(o) { options = o }
export function getOptions(o) { return options }
Then have the user call setOptions() and call this getOptions internally. I realize that since Node requires the module just once that my options object will be kept configured as I pass it around.
NPM modules should IMO be agnostic as to where configuration is stored. That should be left up to the developer, and they may pick their favorite method (env vars, rc files, JSON files, whatever).
The configuration can be passed to your module in various ways. A common way is to export a function that takes an options object:
export default options => {
let db = database.connect(options.database);
...
}
From there, it really depends on what exactly your module provides. If it's just a bunch of loosely coupled functions, you can just return an object:
export default options => {
let db = database.connect(options.database);
return {
getUsers() { return db.getUsers() }
}
}
If you want to allow multiple versions of that object to exist simultaneously, you can use classes:
class MyClass {
constructor(options) {
...
}
...
}
export default options => {
return new MyClass(options)
}
Or export the entire class itself.
If the number of configuration options is limited (say 3 or less), you can also allow them to be passed as separate arguments, instead of passing an object.

Resources