Share Types
One interface file imported by both sides, the contract that makes RPC typed end to end.
The recommended setup is a monorepo where your frontend and workers share TypeScript directly. The RPC contract is then just an interface file: no schema language, no codegen, no drift.
The contract file
Write the service's interface in its own module, together with the JSON shapes it speaks. Keep it free of framework imports so any bundle can consume it:
The server implements it
implements is what keeps the contract honest: change a signature on either side and the compiler objects.
Where a procedure takes a structured argument, the server pairs the JSON interface with a @SerializableObject class that implements it. The class is the runtime shape (deserialization + validation), the interface is the contract:
The client consumes it
Callers send plain object literals matching the JSON interfaces, and the server's @RpcArgument(() => CreateNoteInput) turns them into validated class instances on arrival. The client never needs the class.
Bundle hygiene
- Frontends import only the contract module. The service module pulls in framework decorators, the ORM, and the rest of the worker, none of which belongs in a browser bundle. This is why the interface lives in its own file.
- Interfaces are erased at build time; enums are not. If your contract includes TypeScript enums, they're runtime values; importing them into the frontend is fine and intended, just know the file isn't purely type-only.
- In a monorepo, "sharing" is an import path (
@your-app/shared/NoteServiceInterface). Publishing a types package achieves the same across repos, at the cost of a versioning step, one more reason the monorepo is the recommended shape.
A sharp edge
@InjectRequestContext() parameters that sit between regular arguments must appear in the shared interface as an explicit placeholder slot the caller passes undefined for; the server overwrites it at dispatch. Trailing context parameters can simply be omitted from the interface. Prefer putting context parameters last.