Skip to content

TC39 Decorators ​

What is TC39? ​

TC39 (Technical Committee 39) is the standards body responsible for evolving the JavaScript language.
It is a committee of Ecma International made up of representatives from browser vendors, tooling companies, and the wider JavaScript community.

TC39 defines the official ECMAScript specification progress through a 5-stage process (Stage 0 → Stage 4):

StageNameMeaning
0StrawpersonInformal idea — no specification yet
1ProposalAccepted for consideration; champion assigned
2DraftPrecise semantics being specified
3CandidateFeature-complete; feedback from implementations requested
4FinishedIncluded in the next ECMAScript annual release

The TC39 Decorator Proposal reached Stage 3 and was officially added to the ECMAScript annual edition.
You can follow its status and specification directly on the proposal repository:

🔗 tc39/proposal-decorators

TC39 Decorators in TypeScript ​

TypeScript 5.0 (released March 2023) added native support for TC39 standard decorators.
These are fundamentally different from the older experimentalDecorators flag and do not require any compiler flag.

Available from TypeScript 5.0+

TC39 decorator mode is supported starting with TypeScript ≥ 5.0.
If your project targets TypeScript < 5.0, you must use Legacy mode (experimentalDecorators: true).

Quick comparison ​

Modetsconfig.jsonTS version requiredField syntax
TC39(no flag needed)≥ 5.0fieldName!: Type
LegacyexperimentalDecorators: true≥ 3.4declare fieldName: Type

Using TC39 mode with QuickModel ​

To enable TC39 standard decorators, simply omit the experimentalDecorators flag (or set it to false) in your tsconfig.json:

json
{
	"compilerOptions": {
		"target": "ES2022",
		"lib": ["ES2022"]
	}
}

Then use ! (definite assignment assertion) instead of declare for all decorated fields:

typescript
// TC39 mode — no experimentalDecorators flag
@Quick({
	name: String,
	createdAt: Date,
})
class User extends QModel<IUser> {
	name!: string; // ✅ TC39: use ! (not declare)
	createdAt!: Date; // ✅
}

Per-field with @QType ​

typescript
// TC39 mode — @QType with !
@Quick()
class Post extends QModel<IPost> {
	@QType(Date)
	publishedAt!: Date; // ✅ TC39 mode

	@QType(String)
	title!: string; // ✅
}

TC39 without @Quick

In TC39 mode, field initializers run automatically (controlled by useDefineForClassFields, which defaults to true for ES2022+ targets). Omitting @Quick() can cause field initializers to shadow QuickModel's getters/setters. Always pair @Quick() with any @QType() usage in TC39 mode.

Legacy mode still supported ​

QuickModel fully supports both decorator modes. Legacy mode (experimentalDecorators: true) remains available for projects that cannot upgrade to TypeScript 5.0 or rely on tools that require the older decorator semantics.

See Installation for full tsconfig.json examples for both modes.

Further reading ​