@babel/plugin-proposal-class-properties is a Babel plugin that transforms static class properties as well as properties declared with the property initializer syntax. This plugin enables modern JavaScript class property syntax to be compiled to older JavaScript environments that don't natively support this syntax.
npm install --save-dev @babel/plugin-proposal-class-propertiesThe plugin is designed to be used in Babel configuration files rather than directly imported in code:
// babel.config.js
module.exports = {
plugins: ["@babel/plugin-proposal-class-properties"]
};// .babelrc
{
"plugins": ["@babel/plugin-proposal-class-properties"]
}For programmatic usage:
const babel = require("@babel/core");
const classPropertiesPlugin = require("@babel/plugin-proposal-class-properties");
const result = babel.transformSync(code, {
plugins: [classPropertiesPlugin]
});This plugin transforms class properties from modern JavaScript syntax to compatible older syntax:
Input (Modern Syntax):
class Example {
// Instance property with initializer
message = "Hello World";
// Static property
static version = "1.0.0";
// Computed property
["computed" + "Prop"] = true;
}Output (Transformed):
class Example {
constructor() {
this.message = "Hello World";
this["computed" + "Prop"] = true;
}
}
Example.version = "1.0.0";The main plugin export that creates a Babel transformation plugin using the declare helper from @babel/helper-plugin-utils.
/**
* Default export - Babel plugin function created using declare()
* @param api - Babel API object with version assertion
* @param options - Plugin configuration options
* @returns Babel plugin configuration object created by createClassFeaturePlugin
*/
declare function default(api: BabelAPI, options: Options): BabelPlugin;
interface BabelAPI {
assertVersion(version: number): void;
}
interface BabelPlugin {
name: string;
manipulateOptions: (opts: any, parserOpts: any) => void;
visitor: object;
}Configuration interface for customizing plugin behavior. This interface is exported as a named export.
/**
* Configuration options interface - exported as named export
*/
export interface Options {
/**
* Enable loose mode transformation for better performance.
* When true, uses simple property assignment instead of Object.defineProperty.
* @default false
*/
loose?: boolean;
}Usage with options:
// babel.config.js
module.exports = {
plugins: [
["@babel/plugin-proposal-class-properties", { loose: true }]
]
};Loose mode transformation:
Input:
class Example {
prop = "value";
}Output (loose: false - default):
class Example {
constructor() {
Object.defineProperty(this, "prop", {
configurable: true,
enumerable: true,
writable: true,
value: "value"
});
}
}Output (loose: true):
class Example {
constructor() {
this.prop = "value";
}
}The plugin automatically enables required Babel parser plugins:
/**
* Parser plugins automatically enabled by this plugin
*/
interface ParserPlugins {
classProperties: true;
classPrivateProperties: true;
}This means you don't need to manually configure the parser when using this plugin.
Transforms instance properties with initializers to constructor assignments:
// Input
class User {
name = "Anonymous";
isActive = false;
}
// Output
class User {
constructor() {
this.name = "Anonymous";
this.isActive = false;
}
}Transforms static properties to assignments after the class declaration:
// Input
class Config {
static version = "1.0.0";
static debug = process.env.NODE_ENV === "development";
}
// Output
class Config {}
Config.version = "1.0.0";
Config.debug = process.env.NODE_ENV === "development";Supports computed property names:
// Input
class Dynamic {
[Symbol.toStringTag] = "Dynamic";
["prop_" + Math.random()] = true;
}
// Output
class Dynamic {
constructor() {
this[Symbol.toStringTag] = "Dynamic";
this["prop_" + Math.random()] = true;
}
}When used with private property syntax (requires additional parser configuration):
// Input (with private properties enabled)
class Secure {
#secret = "hidden";
publicMethod() {
return this.#secret;
}
}
// Output varies based on private properties plugin configurationThis plugin is included in:
@babel/preset-env (when targeting environments that don't support class properties)@babel/preset-typescript (for TypeScript compilation)The plugin uses these internal Babel helpers:
@babel/helper-create-class-features-plugin: Core transformation logic@babel/helper-plugin-utils: Plugin declaration utilitiesWhen using Babel assumptions, this plugin respects the setPublicClassFields assumption:
// babel.config.js
module.exports = {
plugins: ["@babel/plugin-proposal-class-properties"],
assumptions: {
"setPublicClassFields": true // Similar to loose: true
}
};The plugin handles several edge cases and error conditions:
Common error patterns to avoid:
// Problematic: Using 'super' in property initializer
class Child extends Parent {
// This will cause runtime errors in some cases
prop = super.getValue(); // Avoid this pattern
}
// Better: Initialize in constructor
class Child extends Parent {
constructor() {
super();
this.prop = super.getValue();
}
}