#Sharing types between backend and frontend apps

1 messages · Page 1 of 1 (latest)

night spruce
#

I have a folder myProject with a backend (Node) and a frontend (Vue.js) folder. Each folder is a separate project with its own individual package.json and tsconfig.json. However, the backend and frontend apps communicate JSON via websockets and it would be handy if I could define the valid types of JSON messages in a common message-types.ts. It could look like this:

export type HelloMessage = { type: "hello" }
export type GoodbyeMessage = { type: "goodbye" }
export type WebsocketMessage = HelloMessage | GoodbyeMessage;

Now, I've tried to put this in a common folder inside myProject like so:

myProject
├── frontend
│   ├── src
│   │   └── main.ts
│   ├── package.json
│   └── tsconfig.json
├── backend
│   ├── src
│   │   └── main.ts
│   ├── package.json
│   └── tsconfig.json
└── common
    └── message-types.ts

Then inside myProject/backend/src/main.ts I would import the types like so: import { WebsocketMessage } from "../../common/message-types.ts". This works, but it results in my backend build to suddenly have a structure like build/backend/src/main.js instead of simply build/main.js like before. Of course, this is because tsc have decided that my rootDir now is myProject instead of backend/src like before.

How can I avoid this? I'm only interested in importing types, so basically tsc doesn't need to output any files for message-types.ts so it doesn't need to change rootDir anyway. How can I tell it this?

Thank you!

dawn frigate
#

I would recommend avoiding it by avoiding using typescript itself for building your project.

#

using a type-oblivious transpiler like esbuild is faster and doesn't struggle with odd issues like this

#

I am building a reproduction, to see if there's a workaround

dawn frigate
#

okay, if you need a typescript-only solution, the solution is to use tsc --build and project references

#

you'll need to add a tsconfig.json to your common folder like

// project/common/tsconfig.json
{
  "compilerOptions": {
    "composite": true,
    "declaration": true,
    "outDir": "dist",
    "rootDir": ".",
    "module": "esnext",
    "moduleResolution": "bundler"
  },
  "include": ["."],
}
#

then in your project/backend/tsconfig.json you'll add a project reference to common like this

"references": [{"path": "../common/tsconfig.json"}]

this lets typescript skip building those files and just reference them from your backend

#

so they don't wind up in your project/backend/dist folder

#

you will need to build with tsc --build now, though, or typescript will complain "output file has not been built from source file"