Conflict between baseUrl and node_modules when importing - javascript

I have a TS project with the following configuration:
tsconfig.json (partial)
{
"compilerOptions": {
"module": "commonjs",
"baseUrl": "src",
"esModuleInterop": true,
},
"include": [
"src"
]
}
I have a dependency on the stripe NPM package:
{
// ...
"dependencies": {
"stripe": "^8.45.0",
}
}
Then I have the following files:
src/routes/payments/index.ts
src/stripe/index.ts
I am having some trouble with imports in src/routes/payments/index.ts. I want to import the stripe library, not my own code.
This works:
// Uses me the 'Stripe' constructor which is the default export from the package
const stripe = require('stripe')('KEY');
This does not work:
import Stripe from 'stripe';
const stripe = new Stripe('KEY');
I get the following error:
Module '"PROJECT/src/stripe/index"' has no default export.
How do I disambiguate and tell TS I want to use stripe from node_modules?

Can you try to update the tsconfig.json file like this:
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"baseUrl": ".",
"paths": {
"*": [
"node_modules/*",
"src/*"
]
}
}
}

Related

Cannot export Interface in Typescirpt - the requested module does not provide an export named Settings

I am trying to export/import an interface in Typescript but I am getting this error, I am not sure what I am doing wrong here
Uncaught SyntaxError: The requested module '/src/types/settings.ts' does not provide an export named 'Settings'
In my types/settings.ts I have this
export interface Settings {
activeUser: number
}
And I import it like this
import { Settings } from '#/types/settings'
And here is my tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"baseUrl": "./src/",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"paths": {
"#/*": ["src/*"],
},
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"isolatedModules": false
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}
I am using Vue/Vite with Typescript
It is weird that npm run build will work fine, but npm run dev will throw SyntaxError.
I was forced to use import type { ... which in consequence also required same touch for Ref from vue.
Workaround was posted on GitHub for Vite issue 731
Entries in paths are resolved relative to baseUrl. Try this:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#/*": ["src/*"]
}
}
}
… or this:
{
"compilerOptions": {
"baseUrl": "./src/",
"paths": {
"#/*": ["./*"]
}
}
}

The requested module does not provide an export named

I'm translating this javascript project (https://github.com/Legorin/satisfactory-calculator) to typescript.
I'm getting an error when I import the transpiled typescript file in a html script tag.
<script>
var handlers = {}
</script>
<script type="module">
import { Initilatizion } from "./init.js";
handlers.init = Initilatizion.init;
</script>
The error is: Uncaught SyntaxError: The requested module './init.js' does not provide an export named 'Initilatizion'
Here is my init.ts file
import { Belt } from "./belt";
import { Building } from "./building";
import { FactorySpecification } from "./factorySpecification";
import { Fragment } from "./fragment";
import { Item } from "./item";
import { Recipe } from "./recipe";
import { Settings } from "./settings";
// tslint:disable-next-line: no-var-requires
const d3 = require("../third_party/d3.min.js");
export class Initilatizion {
public static loadData(settings) {
const spec: FactorySpecification = FactorySpecification.getInstance();
d3.json("data/data.json").then((data) => {
const items = Item.getItems(data);
const recipes = Recipe.getRecipes(data, items);
const buildings = Building.getBuildings(data);
const belts = Belt.getBelts(data);
spec.setData(items, recipes, buildings, belts);
Settings.renderSettings(settings);
spec.updateSolution();
});
}
public static init() {
const settings = Fragment.loadSettings(window.location.hash);
this.loadData(settings);
}
}
Here is my tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "es6",
"moduleResolution": "node",
"sourceMap": true,
"allowJs": true,
"outDir": "dist",
"sourceRoot": "src",
},
}
Where is my mistake?
You declared the wrong module type in your tsconfig.json!
By setting module to "commonjs" you tell typescript to generate a JavaScript file that uses the commonjs import/export syntax used by nodejs and others.
You however, use the "new" ES6-module import/export syntax in your HTML and therefore have to set module to "esnext" or "es6"!
Related documentation
Note: You shared an invalid tsconfig.json file, I fixed it below
Example tsconfig.json:
{
"compilerOptions": {
"module": "es6",
"esModuleInterop": true,
"target": "es6",
"moduleResolution": "node",
"sourceMap": true,
"allowJs": true,
"outDir": "dist",
"sourceRoot": "src"
},
}

tsconfig path cannot be found

I am working on a nodejs app and I want to configure my path in tsconfig.json but I am having issues with the path configuration I keep getting an error Error: Cannot find module '#environment'. what could be the issue?
tsconfig
{
"compilerOptions": {
"resolveJsonModule" : true,
"target": "es6",
"module": "commonjs" ,
"lib": [
"dom",
"es6"
],
"outDir": "build",
"rootDir": "src",
"removeComments": true ,
"strict": true,
"noImplicitAny": true,
"baseUrl": "./",
"paths": {
"#lime/*": ["src/*"],
"#environment": ["src/config/environment.ts"],
},
"esModuleInterop": true
}
}
Project tree:
src - config - environment.ts
...
- index.js
package.json
tsconfig.json
...
environment.ts
import * as dotenv from 'dotenv';
dotenv.config();
interface Environment {
port: number | string,
baseUrl: string,
databaseUri: string,
}
export const environment: Environment = {
port: process.env.PORT!,
baseUrl: process.env.BASE_URL!,
databaseUri: process.env.DATABASE_URI!
}
in index.ts i imported environment.ts as import { environment } from '#environment'; please what could be wrong?
If you are trying to execute this directly with node or ts-node, you should be aware that tsconfig paths are not resolved by default by node. If you are using tsc for the build (and not webpack or similar to generate a bundle), you can add to your dependencies tsconfig-paths like this:
npm install --save tsconfig-paths
And then execute the code with:
node -r tsconfig-paths/register dist/index.js
If you are using TS code directly with ts-node, you can use:
ts-node -r tsconfig-paths/register src/index.ts
In production is suggested instead to bundle the source with webpack for example, and use a plugin like tsconfig-paths-webpack-plugin) to resolve paths while bundling.
I may not sure, i check the documentation. Seems like paths should be dir. please try this combination.
{
"baseUrl": "./",
"paths": {
"#lime/*": ["src/*"],
"#environment": ["src/config/"],
},
"esModuleInterop": true
}
}
and import like:
import { environment } from '#environment/environment'
tsconfig.json
// prettier-ignore
{
"extends": "#tsconfig/react-native/tsconfig.json", /* Recommended React Native TSConfig base */
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Completeness */
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
/* Path */
"baseUrl": "./src",
"paths": {
"#/*": ["./*"],
"#assets/*": ["assets/*"],
"#components/*": ["components/*"],
"#hooks/*": ["hooks/*"],
"#lib/*": ["lib/*"],
"#ui/*": ["ui/*"],
}
},
"exclude": [
"node_modules",
"babel.config.js",
"metro.config.js",
"jest.config.js"
]
}
babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module-resolver',
{
root: ['./src'],
extensions: [
'.ios.ts',
'.android.ts',
'.ts',
'.ios.tsx',
'.android.tsx',
'.tsx',
'.jsx',
'.js',
'.json',
],
alias: {
'#': './src',
'#assets': './src/assets',
'#components': './src/components',
'#hooks': './src/hooks',
'#lib': './src/lib',
'#ui': './src/ui',
},
},
],
],
};

typescript: How to extend existing module definition?

I have a declaration file written for extsting npm package, but seems like one method was not declared, I try to declare it, but get an error. Help me please.
structure of existing d.ts file:
declare module "mongoose" {
...
class Document {}
interface Document extends MongooseDocument, NodeJS.EventEmitter, ModelProperties {
increment(): this;
remove(fn?: (err: any, product: this) => void): Promise<this>;
...
}
}
I try to add to interface Document method deleteOne. My custom.d.ts:
declare module "mongoose" {
interface Document {
deleteOne(fn?: (err: any, product: this) => void): Promise<this>;
}
}
But still I get an error "Property 'deleteOne' does not exist on type".
Here is my tsconfig.json if you need:
{
"compilerOptions": {
"module": "commonjs",
"removeComments": true,
"esModuleInterop": true,
"moduleResolution": "node",
"allowJs": true,
"allowSyntheticDefaultImports": true,
"pretty": true,
"resolveJsonModule": true,
"sourceMap": true,
"target": "ES2018",
"outDir": "dist",
"baseUrl": ".",
"paths": {
"*": [
"node_modules/*"
]
}
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist",
"**/*.spec.ts"
]
}
My custom.d.ts file located in 'src/' dir.
OK! Now I know this is expected behavior of ts-node: https://github.com/TypeStrong/ts-node#missing-types
I have configured paths settings in tsconfig.json, and now everything is working:
"paths": {
"mongoose": ["src/custom.d.ts"],
"*": [
"node_modules/*"
]
}
defining the Mongoose interface
// types/mongoose/index.d.ts
declare module 'mongoose' {
namespace Mongoose {
export interface MyInterface {
name: number;
}
}
}
usage
// app.ts
import mongoose, { Mongoose } from 'mongoose';
const a: Mongoose.MyInterface = {
name: 122
};
I have also added "typeRoots": ["./node_modules/#types", "./server/types"], to my tsconfig file
does this help

How to set alias path via webpack in CRA (create-react-app) and craco?

I have a problem on set webpack alias path using create-react-app and craco, already googling it but can't solve the problem.
I got an error Module not found: Can't resolve '#app/App' in 'C:\ReactSandbox\my-project\src everytime i run application using command yarn start
Steps to reproduce:
create-react-app my-project
cd my-project
yarn add #craco/craco
cat > craco.config.js (see configuration below)
replace react-scripts to craco on 'script' section on package.json (craco start, craco build, etc)
edit file src/index.js (replace line 4, see code below)
yarn start
craco.config.js
const path = require("path");
module.exports = {
webpack: {
resolve: {
alias: {
"#app": path.resolve(__dirname, "src/"),
}
}
}
};
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from '#app/App'; //replace './App' into '#app/App'
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
Current result
Module not found: Can't resolve '#app/App' in 'C:\ReactSandbox\my-project\src
Expected
I'm avoiding call relative path hell, instead of import module like ../../../../FilterComment.js, it would be clean to write #app/FilterComment.js
resolve for carco:
u need install craco-alias, then will write in
craco.config.js
const CracoAlias = require('craco-alias')
module.exports = {
plugins: [
{
plugin: CracoAlias,
options: {
source: 'tsconfig',
baseUrl: '.',
tsConfigPath: './tsconfig.path.json',
},
},
],
}
tsconfig.path.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#/*": ["src/*"],
"#svg/*": ["src/assets/svg/*"],
"#img/*": ["src/assets/images/*"],
"#icons/*": ["src/assets/icons/*"],
"#shared/*": ["src/shared/*"],
"#components/*": ["src/components/*"],
"#hooks/*": ["src/hooks/*"],
"#constants/*": ["src/constants/*"],
"#layout/*": ["src/layout/*"],
"#services/*": ["src/services/*"]
}
}
}
tsconfig.json
{
"extends": "./tsconfig.path.json",
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"checkJs": false,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"noFallthroughCasesInSwitch": true,
"removeComments": true
},
"include": [
"src",
"src/configs",
"react-app-env.d.ts"
]
}
First - tell to IDE about aliases in tsconfig.json:
create separate file tsconfig.paths.json and add aliases:
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"#utils/*": ["utils/*"]
}
}
}
Add created tsconfig.paths.json to main tsconfig.json
{
"extends": "./tsconfig.paths.json",
... other staff ...
}
Second - tell to webpack about aliases:
Add aliases to config-overrides.js
const {
override,
addWebpackAlias
} = require('customize-cra');
const path = require("path");
module.exports = override(
addWebpackAlias({
"#utils": path.resolve(__dirname, "./src/utils"),
}),
);
my craco.config.js look likes below, it works:
const path = require('path');
module.exports = {
// ...
webpack: {
alias: {
'#': path.join(path.resolve(__dirname, './src')),
}
}
}
Just keep your file craco.config.js just like this, and you need to add 1 more file with named jsconfig.json
it's content:
{
"compilerOptions": {
"module": "commonjs",
"target": "es2016",
"jsx": "preserve",
"checkJs": true,
"baseUrl": "./src/",
"paths": {
"#app/*": ["./*"]
}
},
"exclude": ["node_modules", "**/node_modules/*"]
}
then you can import from the absolute path like #app/FilterComment.js
It also worked for VSCode (editor now understand where #app point to).
But if you want VSCode to do the import automatically, then you should add more config for it to force it always do the import from absolute path.
file .vscode/settings.json
content:
{
"javascript.preferences.importModuleSpecifier": "non-relative"
}
An example (which I'm using) without using dependency:
//craco.config.js
const path = require('path')
const tsconfig = require('./tsconfig.base.json')
const removeAsterisk = path => path.replace('/*', '')
const aliasProps = Object.entries(tsconfig.compilerOptions.paths).map(([key, value]) => {
const newKey = removeAsterisk(key)
let newValue = removeAsterisk(value[0])
newValue = path.resolve(__dirname, newValue)
return [newKey, newValue]
})
const alias = Object.fromEntries(aliasProps)
module.exports = {
webpack: {
alias,
},
}
//tsconfig.base.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"~/*": ["./src/*"],
//...
}
}
}
// tsconfig.json
{
"extends": "./tsconfig.base.json",
"compilerOptions": {/*...*/}
}
Use react-app-alias:
Install craco and react-app-alias and create craco config:
// craco.config.js
const {CracoAliasPlugin} = require('react-app-alias')
module.exports = {
plugins: [
{
plugin: CracoAliasPlugin,
options: {}
}
]
}
Replace react-scripts with craco in package.json.
Create typescript config and alias in separated config like this:
// tsconfig.paths.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"example/*": ["example/src/*"],
"#app/*": ["app/src/*"]
}
}
}
// tsconfig.json
{
"extends": "./tsconfig.paths.json",
// ...
}
Now you can do import like this:
import App from '#app/App'
Maybe the OP had a different version of React / Webpack (I'm using today's current versions), but putting the alias object directly inside the webpack object (without nesting it in the resolve object) did the trick for me:
const path = require("path");
module.exports = {
webpack: {
alias: {
"#app": path.resolve(__dirname, "src"),
}
}
};
I am using craco-alias plugin for automatic aliases generation for Webpack and Jest.
(I am just an intern but that's how senior developers in my company are using absolute imports in react)
Install
yarn add #craco/craco
yarn add craco-alias
craco.config.js
const CracoAlias = require('craco-alias');
module.exports = {
plugins: [
{
plugin: CracoAlias,
options: {
source: 'tsconfig',
baseUrl: './src',
tsConfigPath: './tsconfig.paths.json', // or wherever you have defined your paths
},
},
],
};
And make sure that you scripts in package.json look like the following
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "craco eject",
...
},
Then It'll work as specified in tsconfig.json.
FYI I have,
"react-scripts": "4.0.3"
"#craco/craco": "^6.3.0"
"craco-alias": "^3.0.1"

Categories