How to create a definition for 'module.exports' function - javascript

I am exporting a function like this which works.
module.exports = function (options: any): RequestHandler {
// Do stuff
}
I am trying to add a definition for the exported function, but I am not sure if this is the right way to do it:
declare global {
export function tsm(options: any): RequestHandler
}
When I try to test it both of the following say that this is valid:
const tsm = require('ts-middleware')
global.tsm() // Gives intellisense
tsm() // Also gives intellisense
It shouldn't give information about global.tsm(), so I think that I created my definition wrong. What is the correct way to create a function definition?
I don't want to use the function like this:
const tsm = require('ts-middleware')
tsm.tsm()
But I do want to use it like this:
const tsm = require('ts-middleware')
tsm()

To define typings for a module, use declare module 'x' {...}. i.e.:
declare module 'ts-middleware' {
export = (option: any): RequestHandler
}
However, you do not really need to do that because you wrote your code in TypeScript. The compiler can generate the typings for you automatically.
You just need to add declaration: true in your tsconfig.json:
// tsconfig.json
{
"compilerOptions": {
"declaration": true
}
}
Also, I would strongly recommend you to write your code using ESM. i.e. instead of module.exports = ...:
// named export, preferred
export function foo(options: any): RequestHandler { ... }
// or default export
export default function foo(options: any): RequestHandler { ... }
// import in TypeScript for named export
import { foo } from 'ts-middleware'
// import in TypeScript for default export
import foo from 'ts-middleware'
// require in JavaScript commonjs
const middleware = require('ts-middleware')
middleware.foo(...)

Related

JavaScript - How to call a method of a imported JS file

How to define a method 'foo' in a javascript file 'test.js' so that I can import that file into another javascript file and call the method 'foo'?
Before going further you'll need to figure out what kind of modules you're using, there're 2 common types of modules that I know CommonJS and ES
In either type of module you're using, in order for you to import your method, you will need to export it as a module first.
The details of their differences are found in the NodeJS document NodeJS Import
For the ES modules you can export your method 'foo' like this:
// normal function
export function foo1() {}
// arrow function
export const foo2 = () => {}
// or this grouping style that I prefer would look more elegant
function foo1() {}
const foo2 = () => {}
// we can export multiple methods at once
export {
foo1,
foo2
}
On the other hand, using the CommonJS module, you can export your method 'foo' like this:
// a single method
module.exports.foo1 = function() {}
module.exports = function foo2() {}
// multiple methods
module.exports = {
foo1: () => {},
foo2: () => {}
}
Once you've exported your methods as modules, you can now import them like this:
import { foo1, foo2 } from './test.js'
const exec = foo1();
or
import * as test from './test.js'
const exec = test.foo2();
Hope this help

How to include functions in namespace when don't have module?

How to include functions in namespace / module when don't have module?
example: I have a namespace:
namespace Java {}
in typescript, usually when we need a function in namespace or module, we add 'export':
namespace Java {
export function version() {
return "java8";
}
}
namespace JavaScript {
function JavaVer() {
return Java.version();
}
}
But if I set module to none:
// tsconfig
"module": "none",
If module is none, I cannot use import / export:
website/sourcecode/main.ts:17:21 - error TS1148: Cannot use imports, exports, or module augmentations when '--module' is 'none'.
17 export function version() {}
so what can I do?
image:
You can use a plain object:
TS Playground
const Java = {
version () {
return "java8";
},
};
const JavaScript = {
JavaVer () {
return Java.version();
},
};
const vJ = Java.version(); // string
const vJS = JavaScript.JavaVer(); // string
console.log(vJ === vJS); // true
It was answered in here: It's actually "can't have any imports or exports at the top level". Imports and exports inside namespaces are fine because they don't export anything from .ts file at runtime, and as long as file remains 'not a module' module=None works fine. Long explanation here

Type syntax for flow type declared module with class and static members

I'm building a flow-type definition for Sequelize and have run into a small problem with the declare section of the flow-type.
Specifically Sequelize generally is defined as:
class Sequelize {
....
}
Sequelize.DataTypes = DataTypes;
I can generate a flow-type declaration for either one but not both simultaneously. When I put DataTypes in a class they're member variables not available to the instantiated scope.
declare export default class sequelize$Class {
constructor(...);
DataTypes: sequelize$DataTypes;
}
declare var DataTypes: sequelize$DataTypes;
declare export var DataTypes;
Since I need to write code that looks like:
const db = new Sequelize(...)
const MyModel = db.define(... { email: { type: Sequelize.DataTypes.STRING } })
For the moment I've ended up putting this in place:
import Sequelize, { DataTypes } from "sequelize";
const sequelize: sequelize$Sequelize = ((new Sequelize(settings.database, { logging: false })): any);
There has to be a better way.
I'm going to give this a shot and let me know if it helps you out :)
You can declare the sequelize definition like so
declare module 'sequelize' {
declare type sequelize$DataTypes = {
STRING: string
}
declare export default class sequelize$Class {
static DataTypes: sequelize$DataTypes;
constructor(database: Object, options: Object): void;
}
declare export var DataTypes: sequelize$DataTypes;
}
This gives you a default export as well as a named export. I pre-define sequelize$DataTypes, pass it into sequelize$Class as a static property, and export it.

Ionic 2 Angular 2 Global Import Extension methods

I've made some extensions to the Date prototype like:
interface Date {
YearsFromToday(): number;
}
Date.prototype.YearsFromToday = function (): number {
// implementation
}
I'm using the ionic2 tutorial --v2 template, which is a pretty standard layout - app.html, app.ts, app.module etc.
I was wondering if there was an easy way to have this declared globally. I'm not sure exactly where to put this in the project?
Put your monkey patch code in a file.
You might call it monkey-patch-date.ts, for example:
monkey-patch-date.ts
interface Date {
YearsFromToday(): number;
}
Date.prototype.yearsFromToday = function (): number {
// implementation
}
and then import it in main.ts or whatever your entry module is:
main.ts
import './monkey-patch-date';
Alternately. You can make it a module that exports its monkey-patcher if you want to be extra explicit to call out that you are doing something dangerous.
monkey-patch-date.ts
declare global {
interface Date {
yearsFromToday(): number;
}
}
export default function () {
Date.prototype.yearsFromToday = function (): number {
// implementation
};
}
And import it like
main.ts
import monkeyPatchDate from './monkey-patch-date';
monkeyPatchDate();
Another alternative, especially useful for library authors is to allow monkey-patching but not require it while still exposing the functionality.
Here is an example:
date-augmentations/index.ts
export function yearsFromToday(date: Date): number {
// implementation
}
date-augmentations/monkey-patch.ts
import {yearsFromToday} from './index';
declare global {
interface Date {
yearsFromToday(): number;
}
}
Date.prototype.yearsFromToday = function() {
return yearsFromToday(this);
}
Now a consumer can either monkey patch the Date prototype by running
import 'date-augmentations/monkey-patch';
Can access the functionality by the export without monkey patching anything
import {yearsFromToday} from 'date-augmentations';
const date = new Date('12-12-2023');
const yft = yearsFromToday(date);
console.log(yft); // prints 6

Correctly writing and importing custom node modules

EDIT
This is NOT a TypeScript question but rather a best-practices one. The example in TypeScript but really, the question here is how do I, correctly, expose multiple exports from multiple files that compose a module, and how to correctly import them.
EDIT 2
There's still something not right
So, on my Module2's index I have this:
export * from "./queryFilter";
On Module1 user.ts I import it by using
import { queryFilter as QueryFilter } from "Module2";
(...)
var User = {...}
User.getById = (userId: string) => {
...
}
export { User }
And my Module1's index.ts I export it as
export * from "./model/user";
Then, on my main project I import it using
import * as Schema from "Module1";
var User = Schema.User;
However, this throws an error whenever I try to call User.getById:
Debug: internal, implementation, error
TypeError: Uncaught error: Cannot read property 'getByEmail' of undefined
From this approach, what am I doing wrong???
I'm writing a couple of node modules for the first time ever and I do have some questions regarding proper declaration/usage of this.
So I'm creating a module that will require another custom module, let's call them Module1 and Module2.
So, Module1 is required by the main application, but Module1 also requires Module2.
Now on Module2 I have a bunch of files and on each one I export what I need. Here's a sample:
Module2 - Utils.ts:
"use strict"
const RandomString = require("randomstring");
let randomString = (numCharacters: number) => {
return RandomString.generate({
length: numCharacters,
capitalization: 'uppercase',
charset: 'alphanumeric'
});
}
module.exports.randomString = randomString;
Module2 - queryFilter.ts:
"use strict"
export default class QueryFilter {
name: string;
op: string;
value: any;
scope: string;
constructor(name: string, op: string, value: any, scope: string) {
this.name = name;
this.op = op;
this.value = value;
this.scope = scope;
}
public static GetConditionQuery(filters: QueryFilter[], params: string[]) {
(...)
}
public static queryComparator(value1: any, value2: any, operator: string): any {
(...)
}
}
On Module1, I added Module2 to package.json so when I want to use QueryFilter, for instance, I require it like this:
Module1 - Class.ts:
import { QueryFilter } = require("Module2").queryFilter;
Now my question is, is it enough to export individual items from each file in my Module2 and use it in this fashion? Or should I have a index that would export every file from Module2 so that Module1 can see them?
Something along the lines of:
Module2 - index.ts:
export "./utils"
export "./queryFilter"
(...)
What is the correct way of doing this? I'm a total newb to this and the docs I've read didn't shed any light on this..
Best Regards
Following your last comment, this the 'typescript solution' for creating a module/library. The solution would be similar for "pure" ES6; typings in Typescript just add a small layer of difficulty.
Assuming you write a module/library with multiple files:
func1.ts
export func1(param1: number): string { ... }
func2.ts
export func2(): number { ....}
Create an index.ts which re-exports the interesting parts of your module/lib
export * from './func1'
export * from './func2'
....
Obviously you can choose to (re)export and make public only part of the code e.g. export { thisFunc, thatClass } from './anotheFile'
Compile the module with declarations and commonjs flags, and make sure that the package.json main points to index.js, while the typings entry points to the generated index.d.ts
This module/library can now be used from Javascript or Typescript using an ES6 style import syntax
import { func1, func2 } from 'mymodule'
If this is Typescript, the typings of the 2 functions will automatically be imported too.

Categories

Resources