Typescript TS2339 property does not exist - node.js

this one is head scratcher for me. Can't figure this one out... probably need some fresh eye on the matter
I've got the following code
import express from 'express';
import { isFunction } from 'lodash';
export class Server {
private _server = express();
private _namespace = '/api/v1';
public constructor(private _port: number) {}
public addRoute({ path, handler, method }): this {
var requestHandler = this._server[String(method).toLowerCase()];
if (false === isFunction(requestHandler)) throw new Error('Invalid HTTP method');
requestHandler(path, handler);
return this;
}
}
And I keep getting the same errors, which to me makes no sense at all...
TSError: ⨯ Unable to compile TypeScript:
src/server/main.ts:21:14 - error TS2339: Property '_port' does not exist on type 'Server'.
21 this._port = _port;
~~~~~
src/server/main.ts:22:14 - error TS2339: Property '_server' does not exist on type 'Server'.
22 this._server = express_1.default();
~~~~~~~
src/server/main.ts:23:14 - error TS2339: Property '_namespace' does not exist on type 'Server'.
23 this._namespace = '/api/v1';
~~~~~~~~~~
src/server/main.ts:34:35 - error TS2339: Property '_server' does not exist on type 'Server'.
34 var requestHandler = this._server[String(method).toLowerCase()];
~~~~~~~
This is just bonkers to me...
I'm using typescript 3.6.3, running on node 12.8.1 and using ts-node 8.4.1 to plugin TS support
I've pasted the code on type the whole code on TS playground. Made some changes to remove the imports and undefined functions, but overall the above errors do not appear, so I'm kind stomped... if anyone would be kind to point me in the direction of solving this problem that would be fantastic :)
Also, here is my tsconfig.json
{
"compilerOptions": {
"noImplicitThis": false,
"rootDir": "src",
"typeRoots": ["node_modules/#types", "#types"],
"lib": ["es6"],
"strict": true,
"strictPropertyInitialization": false,
"strictFunctionTypes": true,
"esModuleInterop": true,
"target": "es6",
"noImplicitAny": false,
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": false,
"pretty": true,
"outDir": "build",
"alwaysStrict": false,
"noImplicitReturns": true,
"noStrictGenericChecks": true,
"noUnusedLocals": true,
"noUnusedParameters": false,
"suppressImplicitAnyIndexErrors": true,
"preserveConstEnums": false,
"strictNullChecks": true,
"allowSyntheticDefaultImports": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true
},
"include": ["./**/*.ts"],
"compileOnSave": true,
"exclude": ["node_modules"]
}

I've finally figured out what has happened. A clue was that the errors reported has been reporting errors on an already transpiled code. Typescript was ran against a JS code...
What the issue was I was starting the server using nodemon and requiring ts-node again manually. This was the command I've been using
nodemon --ext ts --delay 100ms -r ts-node/register src/app.ts
And it was fine (and even needed) when on my previous project which used nodemon 1.18.9.
But, when I was setting up a new project I've automatically upgraded nodemon to version 1.19.2 and as one can check in nodemon v1.19.0 release notes the TS has been added to default exec path. So, once the nodemon figures out you are running TS files it will change the final node command
FROM
node -r ts-node/register src/app.ts
TO
ts-node -r ts-node/register src/app.ts
Which means that the Typescript will be ran twice and the second time it will ran against an already finished transpiled code a.k.a JS code.
Anyways, once I've changed the start-up command to
nodemon --ext ts --delay 100ms src/app.ts
it all worked as expected.
Hope this helps someone should anyone ran into a similar problem

I also had this issue and spent a long time trying to figure out what was wrong. I'm going to leave this here for people who might run into this in the future. It turns out I had a ts-node re-register as part of my code to get a Typescript Worker thread working. If you have this issue, double check if you using ts-node in the code.
const path = require("path");
require("ts-node").register(); // <-- BAD
require(path.resolve(__dirname, "./worker.ts"));

Related

TypeError [ERR_IMPORT_ASSERTION_TYPE_MISSING]: Module "file:///path/to/data.json" needs an import assertion of type "json"

I'm trying to import JSON in nodejs.
// tsconfig.json
...
"lib": ["es2022"],
"target": "es2022",
"module": "nodenext",
"moduleResolution": "node",
...
"resolveJsonModule": true,
...
// .swcrc.json
...
"target": "es2022",
...
"module": {
"type": "nodenext",
...
When I then compile it and run "start": "NODE_ENV=production node --es-module-specifier-resolution=node --experimental-json-modules --no-warnings lib/index.js" I get TypeError [ERR_IMPORT_ASSERTION_TYPE_MISSING]: Module "file:///path/to/data.json" needs an import assertion of type "json".
I then add:
import data from './data.json' assert {type: 'json'}
console.log(data)
I then open up the compiled code and I can see:
import data from"./data.json";console.log(data);
//# sourceMappingURL=index.js.map
At this point I thought maybe it's SWC not compiling the assertation?
I then run tsc --emitDeclarationsOnly and I get Import assertions are not allowed on statements that transpile to commonjs 'require' calls. At this point I have no idea why on earth commonjs has anything to do with it, I'm not using commonjs anywhere am I?
Also I'm using node 18.
What am I doing wrong? I am simply trying to import that json.
Edit: Okay so the reason TS was breaking was because of missing "include": ["src/**/*.ts", "src/**/*.json", "types.d.ts"],. After adding that it now works. Unfortunately SWC is still giving the same error so I cannot run it.
Finally figured it out. There's an experimental option in .swcrc.json that allows you to tell it to keep the assertations.
// .swcrc.json
...
"jsc": {
"experimental": {
"keepImportAssertions": true
}
}

How to pass separate TypeScript config for TSNode when it has being indecency running by Mocha & IntellIJ IDEA?

Although TS-Node started the ECMAScript modules support, it has a lot of limitations and below example:
import { assert as Assert } from "chai";
describe("firstTest", (): void => {
it("", (): void => {
Assert.isTrue(true);
});
});
does not work with next settings:
tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "node",
"strict": true,
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"baseUrl": "./",
"paths": {},
"noUnusedParameters": true,
"noImplicitReturns": true
}
}
.mocharc.yaml
extension:
- ts
spec: "**/*.test.ts"
require:
- ts-node/register
- tsconfig-paths/register
Error:
import { assert as Assert } from "chai";
^^^^^^
SyntaxError: Cannot use import statement outside a module
I need the ECMAScript modules because the Webpack dynamic loading does not work with CommonJS modules. So the conceptual solution is create the additional tsconfig.json for TSNode or pass modules type via console. It's has been documented how to do it for TSNode, but here I don't execute TSNode directly - I launch the Mocha via IntelliJ IDEA:
IntelliJ IDEA and, I suppose, all IDEs of this family including WebStorm generates the below command (added the line breaks):
"C:\Program Files\nodejs\node.exe"
"D:\XXX\MyProject\node_modules\mocha\bin\mocha" --require ts-node/register --ui bdd --reporter C:\Users\XXX\AppData\Local\JetBrains\Toolbox\apps\IDEA-U\ch-0\203.7148.57\plugins\NodeJS\js\mocha-intellij\lib\mochaIntellijReporter.js
"D:\XXX\MyProject\Test\Test.test.ts" --grep "^firstTest "
Now how to set CommonJS modules type?
According to ts-node's documentation (search for IntelliJ), you can create an alternative tsconfig.json (containing the option "module": "CommonJS") and enforce it for Mocha tests using environment variable TS_NODE_PROJECT. In the configuration corresponding to your Mocha testing, in the Environment variables section, you set this variable to the pathname of this alternative tsconfig.json. Note, multiple tsconfig.json files can use one common "base" file and extend/partially override it (see).

Exporting Global Styles with Font Assets from a TypeScript->CommonJS module

I have a TypeScript React project organized as follows:
tsconfig.json
package.json
yarn.lock
lerna.json
node_modules/
packages/
ui-library/
package.json
tsconfig.json
typings.d.ts
src/
fonts/
myfont.ttf
components/
GlobalStyle.tsx
lib/ <-- `tsc` builds to here
web-app/
package.json
src/
components/
The web-app imports the ui-library as a commonjs module in its package.json. This is managed through Yarn Workspaces, hence node_modules being at the root instead of each folder. At one point, the web-app imports GlobalStyle from the ui-lib, which is where the issue occurs.
Error: Cannot find module '../fonts/myfont.ttf'
Require stack:
- /Users/me/sources/myproject/packages/ui-library/lib/styles/GlobalStyle.js...
Here is the original import statement from ui-library/src/GlobalStyle.tsx that causes the issue:
import myFont from "../fonts/myfont.ttf";
const GlobalStyle = () => (
<style global jsx>{`
#font-face {
font-family: "My font family";
src: url(${myFont}) format("truetype");
}
...</style>);
The issue is the require statement in the emitted GlobalStyle.js code, built when I run tsc in the ui-lib folder:
const MYFONT_ttf_1 = __importDefault(require("./myfont.ttf"));
I googled this issue online, and I found you had to add typings for compiling .ttf and other abnormal imports. So I created a typings.d.ts file with this declaration:
declare module "*.ttf" {
const value: string;
export default value;
}
And I included it on ui-library/tsconfig.json as follows:
{
"extends": "../../tsconfig.json",
"exclude": ["lib"],
"include": ["src"],
"files": ["./typings.d.ts"],
"compilerOptions": {
"baseUrl": "src",
"outDir": "lib",
"declaration": true,
"declarationMap": true,
"noEmit": false
}
}
The tsconfig above extends the root tsconfig:
{
"files": ["./typings.d.ts"],
"compilerOptions": {
"module": "commonjs",
"target": "es2019",
"lib": ["dom", "es2019"],
"strict": true,
"jsx": "react",
"moduleResolution": "node",
"isolatedModules": true,
"esModuleInterop": true,
"noUnusedLocals": false,
"forceConsistentCasingInFileNames": true,
"strictNullChecks": true,
"sourceMap": true,
"noEmit": true,
"declaration": false
},
"exclude": ["node_modules"]
}
We are using TypeScript 3.8. Let me know if there is any additional info to provide. My hunch is that I am either using the wrong module/target, or fundamentally misunderstanding some aspect of this.
More Details
I should note the reason we are using CommonJS modules is because ts-node can only work with that. We pull in ts-node when we are doing our gatsby build, following the gist here in gatsby-config.js:
require("ts-node").register();
// Use a TypeScript version of gatsby-config.js.
module.exports = require("./gatsby-config.ts");
Maybe it's an impossible problem to solve, to get fonts imported through ts-node which is a server side environment? Confused on what the right approach is to export a module with fonts. Willing to get rid of ts-node, and leave the Gatsby config files as js.. but mostly just want to be able to import my fonts.
I solved this by just copying the fonts as part of build steps. Basically, fonts have their own pipeline. There may be better ways, but this works well enough.

importing class in Node js with typescript

I would import class in nodejs and use it in app.ts
var nano = require("nano");
import { EnvConfig } from './envConfig.service';
let config = new EnvConfig();
const dbCredentials: any = config.appEnv.getServiceCreds('dataservices');
export const nanodb = nano({
url: dbCredentials.url,
});
export const nanodbCockpitLight = nanodb.use('data');
console.log(dbCredentials);
When I try to compile I get this error.
import { EnvConfig } from './envConfig.service';
^
SyntaxError: Unexpected token {
I have created the tsconfig file :
{
"compilerOptions": {
"module": "commonjs",
"declaration": false,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"allowSyntheticDefaultImports": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"target": "es6",
"sourceMap": true,
"allowJs": true,
"outDir": "./dist",
//"baseUrl": "src" // Attention !! nécessite l'utilisation d'un loader de module node pour fonctionner sur node
},
"include": ["src/**/*"],
"exclude": ["node_modules", "**/*.spec.ts"]
}
I get this warning
No inputs were found in config file 'c:/Users/EHHD05911.COMMUN/Documents/cockpitLight/DB mananger/tsconfig.json'. Specified 'include' paths were '["src//"]' and 'exclude' paths were '["node_modules","/.spec.ts"]'
You cannot run node app.ts file directly that won't work
You need transpiler like babel js or typescript compiler tsc so first transpile to js file and then run node app.js
You're using .js extension, you need .ts extension, e.g.: app.ts instead of app.js.
Make sure you have typescript either in npm global or in dev dependencies.
I suspect whatever you're importing has typescript syntax (strong typing and such), and so running node directly won't work. You need to run tsc first, which will transpile everything to javascript in a dist folder, and then run node dist/app.js.
This is a bit cumbersome though, which is why there is ts-node. It's exactly what it sounds like, a node REPL for typescript. You should be able to run ts-node src/app.ts.
import { something } is a typescript syntax, it won't work in a .js file. That is a separate language. Try using require instead.
Use babel js which is a toolchain that is mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments.
package.json
"dependencies": {
"#babel/polyfill": "^7.0.0",
}
"babel": {
"presets": [
"#babel/preset-env"
]
},
"scripts": {
"start": "server.js --exec babel-node",
}
https://babeljs.io/docs
This will enable/resolve your import statements.

Error importing node modules in TypeScript

I had a problem this morning that was driving me crazy. I'll explain the issue and then I'll provide my answer below (so that others who come across this can get to a solution sooner).
It is very easy to duplicate the issue by just issuing these commands:
tsd query react --action install
mkdir src
echo "import React = require('react');" > src/foo.ts
I also included the following tsconfig.json file in src:
{
"version": "1.6.2",
"compilerOptions": {
"outDir": "./tsdir",
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"isolatedModules": false,
"jsx": "react",
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"declaration": true,
"noImplicitAny": false,
"removeComments": true,
"noLib": false,
"preserveConstEnums": true,
"suppressImplicitAnyIndexErrors": true
},
"files": [
"foo.ts"
]
}
If I try to compile this by simply running the tsc (version 1.6.2) command inside src, I get:
foo.ts(1,24): error TS2307: Cannot find module 'react'.
What I find baffling here is that I've installed the react bindings with tsd but when I run tsc, I get this error. It looks like I've done everything right, so why the error?
So what I eventually figured out was that I need to explicitly include the typings file in my list of "files", i.e.,
{
"version": "1.6.2",
"compilerOptions": {
...
},
"files": [
"foo.ts",
"../typings/react/react.d.ts"
]
}
In other words, I had to include the typings files explicitly in the "files". I don't really know why. I thought tsc was smart enough to look for them itself.
If there is a better solution that doesn't involve having to list all the .d.ts files explicitly in "files", I'm all ears. But I just wanted to point out that this is at least a workaround.

Resources