Importing external dependencies in Typescript - javascript

I am a newbie in typescript/node. I have a typescript file "order.ts" from which I would like to import an external config dependency from "config.ts"
My config file code is as below
let config = {
mongoAddress: "mongodb://localhost:27017/dts",
dataDirectory: "../../data/"
};
module.exports = config;
I am importing the config file in the order file as below
import { config } from "../../config";
However I am getting the TS compiler throwing error "... file not a module". Any clues how I should I be importing my external dependency in typescript

The main part here is you want to export your object instance. You're on the right track with that, but there may be an easier way for you.
In this case something like wrapping it in a class and exporting that:
export class Config {
mongoAddress = 'mongodb://localhost:27017/dts';
dataDirectory = '../../data/';
}
Notice the export before class. The same can be applied to interfaces, enums etc. By exporting it this way you can then import it and initialise it:
import { Config } from '../config';
var c = new Config();
console.log(c.mongoAddress);
This will not make it a variable, like in your original example, but you'll simply wrap it in a class. This is also why you have to initialise it first using new Config().
Now, I'm assuming you want these properties simply to be accessed globally. And perhaps even static/readonly, so you don't have to initialise the class each time. Making use of the static typing of TypeScript, the sample would in this case be better refactored to something like this:
export class Config {
public static readonly mongoAddress: string = 'mongodb://localhost:27017/dts';
public static readonly dataDirectory: string = '../../data/';
}
With this, calling it is even less obtrusive - and very type safe:
console.log(Config.mongoAddress);
console.log(Config.dataDirectory);
Now exporting this way is just one of the options. It actually depends entirely on the library structure you're using throughout your application (or from third partie libraries, for that matter). It's a bit of dry reading, but I recommend you have a look at the different structures to get acquainted with terms like UMD and modules and how they relate to an import.
Hope this helps!

There are 2 ways you can do import and export.
1) default export
// config.ts
export const config = {
mongoAddress: "mongodb://localhost:27017/dts",
dataDirectory: "../../data/"
};
export default config;
// your other file
import configs from './config';
Note: Here you can give any name for the imported module;
2) normal export with exact declaration name while importing.
// config.ts
export const config = {
mongoAddress: "mongodb://localhost:27017/dts",
dataDirectory: "../../data/"
};
// your other file
import { config } from './config';
Note: Here you have to give the exact name of the module that you exported.
Best practices to follow while exporting configs.
create a static class with static variables in the code. Which likely means that these configs are fixed stuffs.

module.exports is the node syntax for exporting modules. Typescript has a keyword names export so you can just use this:
export const config = {
mongoAddress: "mongodb://localhost:27017/dts",
dataDirectory: "../../data/"
};

Related

What is a good practice to encapsulate multiple JavaScript files within 1 ES6 module?

Having a C# / C++ packaging structure in mind, how do I achieve to have JS-classes in individual files all imported as a single name space?
My currently working solution is to use an additional "package"-script file, which then encapsulates all classes. See the code below.
It seems as this includes a lot of overhead (updating the package-script-exports with every new class, importing this script in every new class).
ClassA.js:
import * as MyPackage from "../MyPackage.js";
export default class ClassA {/* some Class Code */}
export {
ClassA
};
MyPackage.js:
import ClassA from "./module/ClassA.js";
import ClassB from "./module/ClassB.js";
export {
ClassA,ClassB
}
script.js:
import * as MyPackage from "./MyPackage.js"
let a = new MyPackage.ClassA();
What would be a best practice for that?
My currently working solution is to use an additional "package"-script file, which then encapsulates all classes.
Yes, this is the best practice. The "package" script file is typically called index.js placed in the directory of the package, as that's what the folder path is resolved to when importing.
importing this script in every new class
No, you should not do that. It introduces a circular dependency. As long as your module doesn't depend on any of the other classes, it should not import anything. There is no "package declaration", the module is a standalone file with its own dependencies.
Notice also that you shouldn't export your class twice from the module, the default export is enough. So you'd use
// mypackage/classA.js:
export default class ClassA {
/* some Class Code */
}
// mypackage/index.js:
export { default as ClassA } from "./classA.js";
export { default as ClassB } from "./classB.js";
// your solution of importing, then exporting works as well.
// script.js:
import * as MyPackage from "./mypackage";
const a = new MyPackage.ClassA();
// or
import { ClassA } from "./mypackage";
const a = new ClassA();

Import, rename, and export a function in JavaScript?

With JavaScript what's the shortest way to import a named export, rename it, and export it again?
This code works but it feels more verbose than it should be
import { mock as myFunctionMock } from 'context/myFunction';
export const myFunction = myFunctionMock;
You can combine the import and export like so:
export { mock as myFunctionMock } from 'context/myFunction';
See MDN Docs
Note that you won't actually be able to use myFunctionMock within your code file since you haven't imported it. Neither mock nor myFunctionMock will be defined within this module.
This is a useful shorthand when you're building a library that will be used by other modules or by your end-user.
For example, if you had a utils library that you wanted to export, but you wanted to organize your util functions across several smaller files, such as stringUtils, objectUtils, dataUtils, etc, you can export the contents of those modules within your utils module to create a single, monolithic access point:
stringUtils.js
export function toLower(){}
export function toUpper(){}
objectUtils.js
export function propertyMap(){}
utils.js
export {
toLower as stringToLower,
toUpper as stringToUpper,
} from "stringUtils.js";
export {
propertyMap as objectPropertyMap
} from "objectUtils.js";
I wouldn't generally recommend this approach for internal code as it can make your dependency trees a bit wonky in some cases. It can, however, be extremely useful in situations where you want to import from a common interface but the implementation is dependent on the build (prod vs dev, web vs node, etc)
import { mock as myFunction } from 'context/myFunction';
export { myFunction };
in your original exporter, do:
module.exports = { mock: function () {...}}
When importing, do:
const myFunctionMock = require('file path of exporter');
then to reexport in the same file:
module.exports = {renamedMock: myFunctionMock};
Now any changes to mock will propagate to the other modules where it's referenced (side note, this is node.js in a nutshell).

Import JS web assembly into TypeScript

I'm trying to use wasm-clingo in my TypeScript React project. I tried to write my own d.ts file for the project:
// wasm-clingo.d.ts
declare module 'wasm-clingo' {
export const Module: any;
}
and import like this:
import { Module } from 'wasm-clingo';
but when I console.log(Module) it says undefined. What did I do wrong?
Notes:
clingo.js is the main js file.
index.html and index_amd.html are two example pages
Solution:
I solved the problem like this:
// wasm-clingo.d.ts
declare module 'wasm-clingo' {
const Clingo: (Module: any) => Promise<any>;
namespace Clingo {}
export = Clingo;
}
and
import * as Clingo from 'wasm-clingo';
Here's the source for this solution
I know you found a solution acceptable to you; however, you don't really have any types here, you just have Module declared as any, which gives you no typescript benefits at all. In a similar situation I used #types/emscripten, which provides full type definitions for web assembly modules compiled using emscripten. You simply need to do:
npm install --save-dev #types/emscripten
then change your tsconfig.json types array to add an entry for emscripten.
After that you can just write Module.ccall(...) etc. If you like you could of course write const Clingo = Module and then make calls against that if you want a more descriptive name than Module (which is a terrible name!).
You're welcome ;)
I think the issue is that wasm-clingo exports the module itself but import { Module } from 'wasm-clingo' expects a property.
Try
import Clingo_ from 'wasm-clingo';
const Clingo: typeof Clingo_ = (Clingo_ as any).default || Clingo_;

ES6 module syntax: is it possible to `export * as Name from ...`?

See question title. I found a great reference for the forms of export available, but I have not seen what I'm looking for.
Is it possible to do something like the following?
// file: constants.js
export const SomeConstant1 = 'yay';
export const SomeConstant2 = 'yayayaya';
// file: index.js
export * as Constants from './constants.js';
I.e. this would provide a named export Constants inside of index.js containing all of the named exports from constants.js.
This answer seems to indicate it's not possible in TypeScript; is the same true for pure JavaScript?
(This example is a bit contrived; in reality I'm trying to have a prop-types.js module that uses named exports for internal use within the React package, but also exports the prop type definitions under PropTypes for external consumption. I tried to simplify for the sake of the question.)
No, it's not allowed in JS either, however there is a proposal to add it. For now, just use the two-step process with importing into a local variable and exporting that:
// file: constants.js
export const SomeConstant1 = 'yay';
export const SomeConstant2 = 'yayayaya';
// file: index.js
import * as Constants from './constants.js';
export {Constants};
Today in 2019, it is now possible.
export * as name1 from …;
The proposal for this spec has merged to ecma262. If you're looking for this functionality in an environment that is running a previous JS, there's a babel plugin for it! After configuring the plugin (or if you're using ecma262 or later), you are able to run the JS in your question:
// file: constants.js
export const SomeConstant1 = 'yay';
export const SomeConstant2 = 'yayayaya';
// file: index.js
export * as Constants from './constants.js';
// file: component.js
import { Constants } from './index.js';
const newVar = Constants.SomeConstant1; // 'yay'
// file: index.js
// note, this doesn't have to be at the top, you can put it wherever you prefer
import * as AllExportsFromThisModule from "./index.js"; // point this at the SAME file
export default AllExportsFromThisModule;
export const SOME_CONSTANT = 'yay';
export const SOME_OTHER_CONSTANT = 'yayayaya';

Minimal typescript definition for existing javascript library

I want to use the neat-csv library but it does not provide a typescript definition file. Several blogs mentioned a quick way to create a minimal definition file to get started:
declare var neatCsv: any;
But I don't know what to do with the definition file. Where should it be located? How do you link the definition file with the actual implementation which is located in node_modules/neat-csv. Then how do you import it in an actual typescript file?
The package used the following module import syntax:
const neatCsv = require('neat-csv');
This means that the kind of module is that you need don't use exports { x } of default exports export default x. What you need is the following:
declare module "neat-csv" {
var neatCsv: (input: any, options?: any) => Promise<any>;
export = neatCsv;
}
You can copy the preceding code in a file named declarations.d.ts inside your src folder. Then, you will be able to import it and use it as follows:
import * as neatCsv from "neat-csv";
let csv = "type,part\nunicorn,horn\nrainbow,pink";
neatCsv(csv, { /* options */ });

Categories

Resources