@polyprism/ts-class
v0.3.1
Published
Prisma 6 & 7 generator that emits TypeScript classes from your schema. Pure ESM, zero runtime deps — a maintained replacement for prisma-class-generator. Part of PolyPrism.
Maintainers
Readme
@polyprism/ts-class
A Prisma 6 & 7 generator that emits TypeScript classes with public fields from your schema.prisma. A modern, maintained, ESM-native replacement for the abandoned prisma-class-generator. Part of PolyPrism.
export class User {
id!: string;
email!: string;
name: string | null = null;
role: Role = Role.MEMBER;
}
const u = new User();
u.email = "[email protected]";
// id is Prisma-assigned at insert; name and role already have defaults.Pure ESM, Prisma 7-native, zero third-party runtime dependencies. CI tests against both Prisma 6 and Prisma 7. The generated code imports nothing from PolyPrism itself — drop the generator and your output keeps compiling.
Install
pnpm add -D prisma @polyprism/ts-classConfigure
generator polyprismCodegen {
provider = "polyprism-ts-class"
output = "../generated"
}⚠️ The provider string is the bin name (no
@scope/prefix).
Run
pnpm prisma generateOutput
// generated/Task.ts
import { Priority } from "./enums/Priority.js";
import { TaskStatus } from "./enums/TaskStatus.js";
import type { Project } from "./Project.js";
export class Task {
id!: string;
title!: string;
description: string | null = null;
status: TaskStatus = TaskStatus.TODO;
priority: Priority = Priority.MEDIUM;
points: number = 0;
completed: boolean = false;
projectId!: string;
project!: Project;
tags: string[] = [];
}Use it the obvious way:
const t = new Task();
t.title = "Ship it";
t.priority = Priority.HIGH;
// status, completed, points, tags already have defaults from the schemaEvery enum is also emitted as its own standalone ESM file at <output>/enums/<EnumName>.ts.
What makes class mode distinct
- Real initializer expressions for fields with a TS-representable default (Int/Float literals, Boolean literals, String literals, enum values, list-as-
[], nullable-as-null).new Task()gives you a fully-defaulted instance — no manualObject.assigndance. !definite-assignment for fields Prisma populates at insert time (cuid(),uuid(),now(),autoincrement(),dbgenerated()) — so TypeScript trusts they'll be there at read time without forcing you to write a constructor.- Mixed type-vs-value imports: enum imports auto-promote to runtime imports when used as a default value (e.g.
import { type X, Status }ifStatus.PENDINGappears as a default). The import collector handles this automatically. - Bug fix vs.
prisma-class-generator: anInt @default(90)on aDateTimefield gets!: Date, notDate.parse("90"). Mismatched literal/scalar pairs fall through to!instead of producing nonsense.
What you also get out of the box
- Prisma 6 & 7 compatibility — same generator binary, both Prisma majors. CI tests against both, including the Prisma 7
prisma.config.tslayout. - Pure ESM from day one — not retrofitted from a CJS codebase. No
require(), no.cjsre-export shims. - Zero third-party runtime dependencies. This package depends only on
@polyprism/coreand@polyprism/ts-shared, neither of which has a third-party runtime dep. - Eight
///annotations —@hide,@deprecated,@json(four forms),@type,@name,@normalise,@coerce,@noCoerce. Plusprisma-json-types-generatorshorthand compatibility (/// [TypeName]). - Three-axis naming config — independently control file, type, and field naming.
@db.X(p, s)precision captured as JSDoc so the schema-level info survives codegen.- Optional barrel (
emitIndex = true) with class-mode awareness (export { User }vs.export type { User }).
Migrating from prisma-class-generator
Replace the generator block:
// before generator prismaClassGenerator { provider = "prisma-class-generator" output = "../generated" } // after generator polyprismCodegen { provider = "polyprism-ts-class" output = "../generated" }Audit any
Decimalfields.prisma-class-generatoremitted them asnumber(silently wrong); PolyPrism emits the actualDecimaltype from@prisma/client/runtime/library. Code that was treating Decimal-as-number may need.toNumber()or.toString()calls at boundaries.Delete any manual enum mirror files. PolyPrism always emits standalone ESM enum files at
<output>/enums/.
Config options + annotations
Identical across all ts-* patterns — see the root README for the full config reference and annotation grammar.
When ts-class isn't enough
This package is the plain-class pattern — public fields, no behaviour, no data laundering. Use it when you want the conciseness of a class shape without ceremony, and you're happy assigning fields directly.
If you need any of:
- Setter-driven data normalisation (trim, lowercase, uppercase, nullEmptyToNull on assignment)
- Setter-driven type coercion (
"5"→5on Int,"10.99"→Decimal(10.99)on Decimal, etc.) - Private fields with controlled accessors instead of public-field assignment
- Fluent builder (
User.builder().email("...").build()) User.from(data)static factory for hydrating untrusted shapes (HTTP bodies, Prisma rows)toJSON()that handles BigInt without throwing
...reach for @polyprism/ts-domain-class instead. Same schema, same annotations — domain-class activates @normalise and @coerce semantics at runtime via emitted setters.
Sibling patterns
Same schema, different output shape — just swap the provider:
@polyprism/ts-interface—export interface User { ... }@polyprism/ts-type—export type User = { ... };@polyprism/ts-domain-class— opinionated domain class with getters/setters,@normalise/@coercedata laundering,from(),toJSON(), and a fluent builder
License
MIT © Travis Fitzgerald
