In plain JS we can use import statements with data uri, e.g.:
import { number, fn } from 'data:text/javascript;charset=utf-8;base64,ZXhwb3J0IGNvbnN0IG51bWJlciA9IDQyOwpleHBvcnQgY29uc3QgZm4gPSAoKSA9PiAiSGVsbG8gd29ybGQiOw==';
Or dynamically:
import('data:text/javascript;charset=utf-8;base64,ZXhwb3J0IGNvbnN0IG51bWJlciA9IDQyOwpleHBvcnQgY29uc3QgZm4gPSAoKSA9PiAiSGVsbG8gd29ybGQiOw==')
.then(module => console.log(module));
However, putting the same code in a typescript file gets us a "Cannot find module" error.
My tsconfig.json is as follows:
{
"compilerOptions": {
"module": "esnext",
"lib": [
"esnext",
"es6",
"dom"
],
"moduleResolution": "node",
"outDir": "./build",
"noImplicitAny": false,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"target": "es6",
"jsx": "react"
},
"include": [
"src/**/*", "../addon/build/background.js"
],
"exclude": [
"node_modules",
"**/*.spec.ts"
]
}
Typescript docs on module resolution have no mention of data:... from what I see. Is there a way to get this to work in typescript?
See Wildcard module declarations in the Typescript handbook.
You could do something like this:
// types.d.ts
declare module "data:text/javascript;*" {
export const number: number;
export function fn(): string;
}
// index.ts
/// <reference path="types.d.ts"/>
import { number, fn } from 'data:text/javascript;charset=utf-8;base64,ZXhwb3J0IGNvbnN0IG51bWJlciA9IDQyOwpleHBvcnQgY29uc3QgZm4gPSAoKSA9PiAiSGVsbG8gd29ybGQiOw==';
This tells Typescript that an import matching the data:text/javascript; prefix will expose a number property (as a number type) and an fn property (which returns a string). Adjust the module declaration to fit your importer semantics as appropriate.
Related
I am using the below code in order to import a library (p-limit):
import pLimit, { LimitFunction } from 'p-limit';
const limit = pLimit(20);
let limitConcurrency: LimitFunction
import('p-limit').then((pLimit) => {
limitConcurrency = pLimit.default(20);
});
however, every time I want to compile my code, I get the following error:
Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\User\Documents\GitHub\server\node_modules\p-limit\index.js from C:\Users\User\Documents\GitHub\server\src\controllers\CardsController.ts not supported.
Instead change the require of index.js in C:\Users\User\Documents\GitHub\server\src\controllers\CardsController.ts to a dynamic import() which is available in all CommonJS modules.
My tsconfig.json looks like this:
{
"compilerOptions": {
"target": "es6",
"module": "CommonJS",
"moduleResolution": "node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"lib": ["ES2021"],
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true
},
"include": ["./src/**/*", "types.tsx"],
"exclude": [
"./plugins/**/*",
"./typings/**/*",
"./built/**/*"
]
}
How can I solve this?
I have a function that is a part of my utils package that I import in my other modules:
export function urlQueryParamParser(params: URLSearchParams) {
const output:any = {};
const searchParams = new URLSearchParams(params);
new Set([...searchParams.keys()])
.forEach(key => {
output[key] = searchParams.getAll(key).length > 1 ?
searchParams.getAll(key) :
searchParams.get(key)
});
return output;
}
I export it like this in my index file along with other modules:
export * from './utils/urlQueryParamParser'
When I import it to my module:
import { urlQueryParamParser } from '#mypackages/utils'
and use it urlQueryParamParser(params) I get:
{
"[object Iterator]": null
}
Where, if I just copy the function and use it as a part of the file where I am actually calling it, I get the right return result, something like this:
{
"filter": "all",
"query": "",
"range": "today",
"from": "2022-11-22",
"to": "2022-12-22",
"claims": [
"damaged",
"missing-article"
]
}
Why is the result different when I import this function as part of the other package from when I use it as a function in the file where I am calling it?
The module where I am importing the function has following typescript version:
"typescript": "^4.7.2",
And the tsconfig.json of that module looks like this:
{
"compilerOptions": {
"baseUrl": "./src",
"target": "ESNext",
"allowJs": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"module": "ESNext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"importHelpers": true,
"noEmit": true,
"jsx": "react-jsx",
"skipLibCheck": true
},
"include": ["src/**/*.ts", "src/**/*.tsx"],
"files": ["custom.d.ts"]
}
The typescript version of the package module is:
"typescript": "^4.7.4"
And the tsconfig.json looks like this:
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist/", // path to output directory
"baseUrl": "./src",
"target": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"module": "ESNext",
"allowJs": false,
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"importHelpers": true,
"jsx": "react",
"noEmit": false,
"composite": true,
"incremental": true,
"declarationMap": true,
"plugins": [{ "name": "typescript-plugin-css-modules" }]
},
"exclude": ["**/node_modules", "**/.*/", "dist", "build"],
"include": ["src/**/*.ts", "src/**/*.tsx"]
}
Following up on my comment above.
I am guessing that the reason for this is that you forgot to spread the keys in your array in the file located in the package. Instead, you add the iterator object as the sole child into the array.
I think that you wrote new Set([searchParams.keys()]) instead of new Set([...searchParams.keys()]) in your current or previous version, and this incorrect piece of code got compiled wrongly (maybe it is even cached wrongly somewhere).
That said, I have no idea why TypeScript did not explicitly warn you when you did so. When reproducing the issue, I had to include // #ts-nocheck in my file.
Unfortunately, the issue is quite hard to reproduce since the information you gave was too sparse to create a working project. In the future, I recommend creating a CodeSandbox that contains the issue.
If you're using TypeScript older than the 2.3.1 your TypeScript will not detect the URLSearchParams as an iterable object and then when you try to spread it it should not work then by javascript magic its making it return the [object Iterator] instead of raise an error.
Also your params should be a string (or URL['search'] if you want a better explanation of what is the params when reading your function) since passing the params as a string or the result of an other URLSearchParams return the same thing as the output.
As of why it works on some cases and other don't the only thing that I can think of is that the target version of your tsconfig.json and the typescript of your package.json does not match.
Or this #mypackages is using a different typescript version then the project that is using the function. If you can provide more information about the versions and environment that you're running the function it should be easier to solve the problem.
Shot in the dark here but, does it work if you replace your spread operator with Array.from?
export function urlQueryParamParser(params: URLSearchParams) {
const output:any = {};
const searchParams = new URLSearchParams(params);
new Set(Array.from(searchParams.keys()))
.forEach(key => {
output[key] = searchParams.getAll(key).length > 1 ?
searchParams.getAll(key) :
searchParams.get(key)
});
return output;
}
In your module's tsconfig.json you have set noEmit to false, surely this should be set to true if you want it to actually compile.
Try to import it using its relative path.
import { urlQueryParamParser } from '../mypackages/utils'; // instead of '#packages/utils'
Or update the utils/index.js to:
import { urlQueryParamParser } from "./urlQueryParamParser";
export default {
urlQueryParamParser
};
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"
},
}
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
I have a file named constants.ts which contains constants related to my React TypeScript application.
The file looks like this:
// The error for when errors are bad.
const BAD_ERROR_ERROR = "Something happened that shouldn't have. Please contact an admin";
const Constants = {
APIResponses: {
accounts: {
login: {
account_not_verified: {
message: "You need to verify your email",
problemFields: ["email"]
},
bad_login: {
message: "Your email or password is incorrect",
problemFields: ["email", "password"]
},
default: {
message: BAD_ERROR_ERROR,
problemFields: ["email", "passwords"]
}
}
}
}
};
export default Constants;
I then import it in a TSX file like this:
import Constants from "constants";
and reference a key like this:
const { status } = json;
const resp = Constants.APIResponses.accounts.login[status.message];
However, when I attempt to use it, I get this error:
Property 'APIResponses' does not exist on type 'typeof import("constants")'. TS2339
69 |
70 | const { status } = json;
> 71 | const resp = Constants.APIResponses.accounts.login[status.message];
This error only occurs when importing it from my baseDir as "constants", when importing as ../../constants, it works fine. (That's the work around I'm going with right now)
Here's the things I've tried that haven't worked:
Explicitly defining a type for Constants in constants.ts
Renaming it to constants.js
Casting the type on the default export
Not exporting it as default
Here's the hacky fixes I found that work, but are hacky and undesirable:
Importing it relatively (../../constants) (current)
Casting it to an any type ((Constants as any).APIResponses...)
Here's my tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react",
"rootDir": "./src",
"baseUrl": "./src"
},
"include": [
"src"
]
}