Mongoose Schema pagination typing using mongoose-paginate-ts - node.js

EDIT FIXED :
What I onited say in my initial post is that I was exporting the mongoose-pagination-ts function & interface from a global file, and then importing it in my schema files to use it. However, it appears that I need to import the module directly in each schema file in order for it to work, Interface cannot be export in a file and import in another, comming from a node_module in CommonJS (Apparently, not sure if it's the correct reason)
I'm facing the following issue :
The module mongoose-pagination-ts explains as follow :
import { mongoosePagination, Pagination } from "mongoose-paginate-ts";
type User = mongoose.Document & {
username: String,
accounts: [mongoose.Types.ObjectId]
};
const userSchema = new Schema({
username: String,
accounts: [{ type: ObjectId, ref: "Account" }]
});
userSchema.plugin(mongoosePagination);
const User: Pagination<User> = mongoose.model<User, Pagination<User>>("User", userSchema);
//User.paginate()
The build passes with no issue, but when I execute the server in development mode using the following command I have the bellow issue :
nodemon --ext 'ts,js,cjs,json' --ignore 'tests/' --exec 'ts-node-esm src/index.ts'
import { mongoosePagination, Pagination } from "mongoose-paginate-ts";
^^^^^^^^^^
SyntaxError: Named export 'Pagination' not found. The requested module 'mongoose-paginate-ts' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:
import pkg from 'mongoose-paginate-ts';
const { mongoosePagination, Pagination } = pkg;
at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21)
at async ModuleJob.run (node:internal/modules/esm/module_job:190:5)
tsconfig.js
{
"compilerOptions": {
"experimentalDecorators": true,
"target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
"module": "ESNext" /* Specify what module code is generated. */,
"rootDir": "./src" /* Specify the root folder within your source files. */,
"moduleResolution": "NodeNext" /* Specify how TypeScript looks up a file from a given module specifier. */,
"baseUrl": "./src" /* Specify the base directory to resolve non-relative module names. */,
"outDir": "build",
"types": ["node", "mocha"] /* Specify type package names to be included without being referenced in a source file. */,
"allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */,
"checkJs": false /* Enable error reporting in type-checked JavaScript files. */,
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
"strict": false /* Enable all strict type-checking options. */,
"skipLibCheck": true /* Skip type checking all .d.ts files. */,
"resolveJsonModule": true
},
"ts-node": {
"swc": true
},
"exclude": ["tests", "node_modules"]
}
Any solution is welcomed, thanks !
The error is clear : the module is exported as a CommonJS module and the proposed solution should work, however, the Pagination interface cannot be destructured as explained :
import pkg from 'mongoose-paginate-ts';
const { mongoosePagination, Pagination } = pkg; // Pagination is not found

Related

How to make ts. file keeping the right path after compiled to js file?

My folder structure
Node (root directory)
-data
-123.mp4
-src
-test.ts
-build
-test.js
My ts. file in src folder,
import { createReadStream, createWriteStream } from 'fs';
const readStram = createReadStream('../data/123.mp4')
const writeStream = createWriteStream('../data/copy.mp4')
compiled to build folder,
import { createReadStream, createWriteStream } from 'fs';
const readStram = createReadStream('../data/123.mp4');
const writeStream = createWriteStream('../data/copy.mp4');
I got an error, that said no such file or directory, what should I do to keep js file has the right path to load 123.mp4?
trying to use the path module, but there is another error mentioned __dirname can't use in ES module.
my ts.config
{
"include": ["src/**"],
"exclude": ["node_modules"],
"compilerOptions": {
"target": "ES2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
"module": "Node16" /* Specify what module code is generated. */,
"rootDir": "./src" /* Specify the root folder within your source files. */,
"moduleResolution": "Node16" /* Specify how TypeScript looks up a file from a given module specifier. */,
"outDir": "./build" /* Specify an output folder for all emitted files. */,
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
"strict": true /* Enable all strict type-checking options. */,
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}
Try adding your assets to file
https://www.typescriptlang.org/tsconfig#files

Why am I getting "parserOptions.project" has been set for #typescript-eslint/parser specifically for .test.ts files?

I have been trying to fix this error for .test.ts files for the past three days.
I have my tsconfig as follows
{
"compilerOptions": {
"target": "es6", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
"lib": ["ESNext"], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
"module": "commonjs", /* Specify what module code is generated. */
"rootDir": "./src", /* Specify the root folder within your source files. */
"moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
"baseUrl": "src", /* Specify the base directory to resolve non-relative module names. */
"types": ["jest", "node"], /* Specify type package names to be included without being referenced in a source file. */
"resolveJsonModule": true, /* Enable importing .json files */
"allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */
"checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
"outDir": "./dist", /* Specify an output folder for all emitted files. */
"removeComments": true, /* Disable emitting comments. */
"importsNotUsedAsValues": "error", /* Specify emit/checking behavior for imports that are only used for types */
"isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
"allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
"noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
"noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
"noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
"exactOptionalPropertyTypes": false, /* Interpret optional property types as written, rather than adding 'undefined'. */
"noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
"noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
"noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
"noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
"noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
"allowUnusedLabels": false, /* Disable error reporting for unused labels. */
"allowUnreachableCode": false, /* Disable error reporting for unreachable code. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"include": ["src"],
"exclude": ["node_modules", "dist", "coverage", "src/__tests__", "**/*.test.ts"]
}
And my eslintrc.js has these contents
module.exports = {
env: {
es2021: true,
node: true,
jest: true,
},
extends: [
'eslint:recommended',
'airbnb-base',
'plugin:#typescript-eslint/recommended',
'plugin:#typescript-eslint/recommended-requiring-type-checking',
'plugin:prettier/recommended',
'plugin:import/typescript',
'prettier'
],
parser: '#typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
project: 'tsconfig.json',
tsconfigRootDir: './',
},
plugins: ['#typescript-eslint', 'prettier', 'import'],
rules: {
}
}
In src/__tests__/sample.test.ts I get this error
Parsing error: "parserOptions.project" has been set for #typescript-eslint/parser.
The file does not match your project config: src/__tests__/sample.test.ts.
The file must be included in at least one of the projects provided.
I have noticed that it only occurs for .test.ts files rest of the typescript files with only .ts extension are working fine
What am I missing?
So, since I was excluding the test files in tsconfig,json I had to somehow add those files for eslint to lint during development and also exclude them on build time.
I ended up creating a new file tsconfig.eslint.json with the contents
{
"extends": "./tsconfig.json", <-- since the entire src folder is already included here
"exclude": ["node_modules", "dist", "coverage"] <--- override the exclude property to not have test files here
}
And in my eslintrc.js
parserOptions: {
sourceType: 'module',
project: 'tsconfig.eslint.json',
tsconfigRootDir: './',
},
This fixes the error.

Configure typescript to output imports with extensions, ex: `from './file.js``

Using node 14.x I would like to switch my project to full ES Modules, as it's now supported.
So I enabled on package.json "type": "module"
and my tsconfig.json looks like that:
{
"compilerOptions": {
"outDir": "dist", /* Redirect output structure to the directory. */
"strict": true, /* Enable all strict type-checking options. */
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
"allowSyntheticDefaultImports": true,
"lib": ["ES2020"],
"module": "ESNext",
"moduleResolution": "node",
"target": "ES2020"
}
}
But the output files have unspecified extension in imports, it's instead REQUIRED for node 14.x to specify full file ext
For example:
import { ENV, redisConfig } from './config';
should instead be:
import { ENV, redisConfig } from './config.js';
TS won't handle that for you, but you can run Node with the node --experimental-specifier-resolution=node parameter.
Source
Unfortunately it seems that TS isn't going to support adding extension to the end of the import, since apparently it's not as simple as adding .js to the end of the import.

Typescript declaration file for an external npm package - constructor

I am using ES6 and Typescript for my Node project, however one library is a commonjs library.
For that library, I created my own .d.ts declaration file:
module "#alpacahq/alpaca-trade-api" {
export interface AlpacaParams { ... }
// ...
export class Alpaca implements Broker {
// ...
constructor(params: AlpacaParams);
}
export default Alpaca;
}
Everything works as expected, but I'm having a problem with the constructor.
If I use that class from within my project, and I try this:
this.alpaca = new Alpaca.Alpaca({...});
I get told that Alpaca.Alpaca is not a constructor.
The only way it seems to work is if I do:
this.alpaca = new Alpaca.default({...});
I'm quite new to Typescript, so I'm sure I'm doing something wrong. Any ideas?
The latter works, so I'm not blocked in my work, but I would like to set things up properly.
Thank you!
Edited to show TS config and imports
tsconfig.json
{
"compilerOptions": {
"target": "es6",
"module": "es6",
"lib": ["es6", "es5"],
"sourceMap": true,
"outDir": "dist",
"rootDir": "src",
"strict": true,
"moduleResolution": "node",
"typeRoots": ["./types"],
"esModuleInterop": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
This is how I import it. Couldn't figure out how to make it work otherwise. If I import modules ES6 style, it breaks unless I use commonjs. If I use commonjs, I get an "export undefined" error.
import * as Alpaca from '#alpacahq/alpaca-trade-api';
The problem is that you're importing all named exports with import * meaning that Alpaca refers to the module and .default refers to the exported class. Instead you should be importing just the default member.
Change your import to look like this:
// Import default member from module
import Alpaca from '#alpacahq/alpaca-trade-api';
this.alpaca = new Alpaca({...});

How to reference externally defined node modules with string identifiers with typescript

I'm writing a set of node helper modules in typescript. I'm having difficulty getting typescript to interpret type information for external node modules such as "fs" and "path".
Importantly, I want to separate my module into a bunch of Typescript files, with a class/interface per file. They file layout is like this:
ts/ISomeInterface1.ts
ts/ISomeInterface2.ts
ts/SomeClass1.ts
ts/SomeClass2.ts
A class instantiates one or more interfaces, and is written as follows:
///<reference path="IFileSystemHelpers.ts" />
var fs = require("fs");
namespace myNmspace {
export class SomeClass1 implements SomeInterface1 {
public someIFunction() {
//do work
}
}
}
I'm using gulp-typescript to install type declarations for NodeJs. And I use a tsconfig.json file to build and reference these external typings. Here's a snippet:
{
"version": "1.8.9",
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"preserveConstEnums": true,
"declaration": true,
"suppressImplicitAnyIndexErrors": true,
"out": "./outputfile.js"
},
"filesGlob": [
"./**/*.ts",
"!./node_modules/**/*.ts"
],
"files": [
"./typings/main.d.ts",
"./ts/ISomeInterface1.ts",
"./ts/ISomeInterface2.ts",
"./ts/SomeClass1.ts",
"./ts/SomeClass2.ts",
"./ts/exports.ts"
]
}
Then classes are exported in the exports.ts file:
declare var exports: any;
if (exports) {
exports.SomeClass1 = myNmspace.SomeClass1;
exports.SomeClass2 = myNmspace.SomeClass2;
}
Then comes my problem. How do I get type information for the "fs" module?
I can see the following in the node.d.ts file (see here)that typings has installed:
declare module "fs" {
import * as stream from "stream";
import * as events from "events";
...
}
How do I force Typescript to interpret my fs variable in the SomeClass1.ts file as strongly-typed? In other words, what do I write here:
var fs : ??? = require("fs");
Can anyone help?
As an aside, I've noticed that if I replace the var with an import keyword, I get correct type interpretation for the fs variable. However the terms which point to my interfaces break and I get a squiggly line under the implements ISomeInterface1. Changing the pattern to use imports breaks my file separation, and seems valid only if I want to create a single-file node module.
Use ES6 style imports
import * as fs from 'fs'
import * as path from 'path'
This will also import the definitions from the definition file.
The syntax var x = require('x') does not (however import x = require('x') does, to add to the confusion)

Resources