Sharing typescript types accros different projects - javascript

I am building an app which has 2 repos. One is the frontend, using react, and the other one is a functions repo which is a repo containing cloud functions(the backend is firebase). I want to create another repo which will be a kind of a types repo so the front and the functions repos will share the same types.
Now what i have done is created a libs directory in which i set up a basic tsconfig and src folder with a test interface.
tsconfig in lib directory:
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"composite": true
},
"include": ["src"],
}
The interface i created:
export interface Test {
test: string
}
tsconfig in the frontend directory:
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve"
},
"include": ["src"],
"references": [
{
"path": "../libs/test"
}
]
}
Now i am able to use this interace in the fronend by importing it like this:
import { Test } from "../../../../libs/test/src/test-interface";
But i have a few problems:
I am not able to auto import it. I mean i cant just write the name of the interface and vscode would suggest to import from the right source. I have to manually type the import
I have to manuly build the types directory, and iwould like for it to build automatically when i run npm start in the fronend.
Is there a way to achive that?

You can build your shared repo as an actual package that can be installed (e.g. npm install --save the-shared-types-package ). To do so you have to load the result into something that can be a source for npm packages. Github does have a service that can do that for example: https://docs.github.com/en/packages/learn-github-packages/introduction-to-github-packages - as do many other vendors.
Main trick is you need a kind of publishing workflow on the types repo.

Related

How to debug a "Cannot find module" error in Javascript? MODULE_NOT_FOUND

I have a Typescript project whose tsconfig.json file currently looks like this:
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"target": "es2020",
"baseUrl": "src",
"outDir": "dist",
"declaration": false,
"sourceMap": true,
"esModuleInterop": true,
"newLine": "lf",
"forceConsistentCasingInFileNames": true,
"strict": true,
"strictNullChecks": true,
"importsNotUsedAsValues": "error",
"isolatedModules": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noUncheckedIndexedAccess": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"preserveConstEnums": true
},
"include": ["src"]
}
When I build my project with tsc no problems arise. But when I run it with node dist/server/index.js I get errors like Cannot find module 'server/foo/bar' MODULE_NOT_FOUND.
What tools do developers have to try to debug this?
TypeScript could find the module during transpilation, otherwise it would have failed. Why can't JavaScript find it then?
How can I know where it tried to look for the module? Or any other information that could help the developer figure out how to fix this.
It's not usually tools that developers use to resolve issues like this, but knowledge of how their package manager stores and loads packages.
For instance, if you are using yarn and its Plug'n'Play feature (check whether you have a .pnp.cjs file in your project root where your package.json is located) then running:
yarn node dist/server/index.js
will include plug-and-play in node's module loading (refer to the link above for details) and allow packages to be resolved. When typescript code is compiled the tsc compiler must also be run under yarn to allow modules to be resolved, which is implicitly happening if tsc is being run as a script from your package.json.

Cannot import my published TS library from a separate project

I just created my first JavaScript library (ana.js), I used TypeScript and compiled everything from ~/src/ts/index.ts into the dist directory. This are the compiler options of the library:
{
"target": "es2016",
"lib": ["es2017", "dom", "DOM.Iterable"],
"module": "ES6",
"moduleResolution": "node",
"sourceMap": true,
"outDir": "./dist",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitAny": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"declaration": true
}
Then I created a sample project to test that I published correctly the library. I scaffolded a Vite project and installed the ana.js package. Then, I imported the library in the main.ts file:
import { Ana } from 'ana.js'
console.log(Ana)
When running the Vite server, it throws of missing declarations and references. Uncaught ReferenceError: exports is not defined I think this means I built the library using a wrong module, but I'm not really sure. Any help is welcome. Thank you.

extending tsconfig seems to be getting ignored

I have a tsconfig in the root of my app which gets created by create-react-app. With in the src folder of my app, I have a folder called api which is where I have nodejs server side code. The problem I have, is that the tsconfig of create-react-app does not work for what I need in my server side code.
{
"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",
"noImplicitAny": false,
"downlevelIteration":true,
"baseUrl": "src/",
},
"include": [
"src"
],
"exclude": [
"api"
]
}
The problem is with the "module": "esnext", This option only works for client side code, but wont work for node unless if I have .mjs extension if I understand correctly. In node I need this option set to commonjs. This is causing me to get the following error when running my code
SyntaxError: Cannot use import statement outside a module
So I attempted to create a new tsconfig file inside the api folder which extends the tsconfig of the root of the app. Here is that code.
{
"extends": "../../tsconfig",
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"noImplicitAny": true,
"sourceMap": false,
"noUnusedLocals": true,
"noImplicitThis": true,
"noImplicitReturns": true,
}
}
It feels like this is getting totally ignored however, because I am still getting the exact same error.
EDIT: I added an option to exclude the api folder in my root tsconfig. Still not working.
Any ideas?
While this does not answer my question directly, I did manage to solve my issue by giving ts-node the exact path of the tsconfig I want it to use when running the server side code. Here is what that looks like.
"start:server": "./node_modules/.bin/ts-node --compiler typescript --project src/api/tsconfig.api.json src/api/index_server.ts"

Typescript error in server file for NextJS

I'm using the following package versions:
next v8.1.1-canary.42
#types/next v8.0.5
server.js
import next from 'next';
const app = next({ dev: isDevelopment });
tsconfig.json
{
"compilerOptions": {
"allowJs": true,
"allowSyntheticDefaultImports": true,
"alwaysStrict": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"jsx": "preserve",
"lib": ["dom", "es2017"],
"module": "commonjs",
"moduleResolution": "node",
"noEmit": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"removeComments": true,
"resolveJsonModule": true,
"sourceMap": true,
"strict": true,
"target": "esnext"
},
"exclude": ["node_modules"]
}
I get the following Typescript error:
Cannot invoke an expression whose type lacks a call signature. Type 'typeof import(".../node_modules/next/types/index")' has no compatible call signatures.
I can't understand what's going on here. Can anyone help explain this error and why one of the core functions for this popular package throws it? Do I need to manually extend some Next types for something that's missing?
Since your code actually works with next v8.1.0 (the latest released version) and #types/next v8.0.0, but breaks with next v8.1.1-canary.42, it might just mean that they introduced some incompatible changes that made the existing .d.ts files out of date. The #types/* packages are maintained by independent volunteers for those packages that don't bother publishing the TypeScript type definitions, and are often late to update, especially if we are talking about some pre-released version.
Can you consider using the latest version of next (v8.1.0)?
As an alternative, you might try to understand what changed between versions, and produce your own .d.ts files to use.

relect-metadata shim is required when using class decorators (node)

Using swagger codegen I generated a typescript-angular project and then built it by running npm install. I then wrote a test class and ran tsc to compile it to javascript so that I could run the test class using node. When I tried running the node testing.js command I received the error message "reflect-metadata shim is required when using class decorators." As the is not meant to be a full app I do not have an index.ts or main.ts files and as such other solutions that I came across (such as imports) are not working. When I run npm list I see that I do have reflect metadata in my node modules. Here is my tsconfig file:
{
"compilerOptions": {
"types": ["reflect-metadata"],
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noImplicitAny": false,
"suppressImplicitAnyIndexErrors": true,
"target": "es2015",
"module": "commonjs",
"moduleResolution": "node",
"removeComments": true,
"sourceMap": true,
"outDir": "./dist",
"noLib": false,
"declaration": true,
"lib": [ "es6", "dom" ]
},
"exclude": [
"node_modules",
"dist"
],
"filesGlob": [
"./model/*.ts",
"./api/*.ts"
]
}
Is there a way to run a js file from node when it has decorators?
So seems like I found a workable solution. I added
import "reflect-metadata"
to the first line of the typescript file (It had to be the first line as otherwise it was using decorators before the import had been done).

Categories

Resources