easy-oop
v0.1.0
Published
A small, chainable OOP builder for modern JavaScript.
Maintainers
Readme
EasyOOP
EasyOOP is a small, dependency-free class builder for JavaScript. It creates ordinary classes, so instances behave as expected with new, instanceof, prototypes, and native super.
import OOP from "easy-oop";
const User = OOP
.class("User")
.properties({
name: "",
age: 0
})
.methods({
hello() {
console.log(`Hello ${this.name}`);
}
})
.done();.class() starts a class definition. .properties() adds instance defaults. .methods() adds prototype methods. .done() returns the final class.
Install
npm install easy-oopEasyOOP requires Node.js 18 or newer and supports both ES modules and CommonJS.
const OOP = require("easy-oop");Constructors
Use .constructor() for initialization work.
const User = OOP
.class("User")
.properties({ name: "", age: 0 })
.constructor(function (name, age) {
this.name = name;
this.age = age;
})
.done();
const user = new User("Ada", 36);Inheritance and parent access
Child classes inherit properties and methods. If a child does not declare a constructor, its nearest parent constructor is used. An overriding constructor can call this.super(...). For methods, use normal JavaScript super with concise method syntax.
const Admin = OOP
.class("Admin")
.inheritsFrom(User)
.properties({ role: "admin" })
.constructor(function (name, age) {
this.super(name, age);
})
.methods({
hello() {
super.hello();
console.log("Admin access granted");
}
})
.done();Use concise methods (hello() {}), not arrow functions, when calling super.
Property defaults and validation
Every instance gets its own arrays, plain objects, maps, sets, and dates. A value becomes a validation rule only when it includes type, validate, or factory, so { default: "dark" } remains a normal object default. For values that must be created dynamically, use factory.
const User = OOP
.class("User")
.properties({
tags: [],
createdAt: { factory: () => new Date() },
age: { default: 0, type: Number, validate: (value) => value >= 0 }
})
.done();type accepts a constructor such as String, Number, or your own class. validate must return true; it runs for the default and every later assignment.
Static members
const User = OOP
.class("User")
.staticProperties({ count: 0 })
.staticMethods({
create() {
this.count += 1;
return new this();
}
})
.done();Static methods inherit normally and can use concise-method super as well.
Getters and setters
const Person = OOP
.class("Person")
.properties({ firstName: "", lastName: "" })
.getters({
fullName() { return `${this.firstName} ${this.lastName}`.trim(); }
})
.setters({
fullName(value) { [this.firstName, this.lastName] = value.split(" "); }
})
.done();Mixins
Mixins are small reusable method objects.
const CanLog = OOP.mixin({
log(message) { console.log(message); }
});
const User = OOP.class("User").uses(CanLog).done();Private and protected-style data
JavaScript cannot expose truly private fields to methods supplied in an object literal without changing the method syntax. EasyOOP therefore provides non-enumerable stores available inside methods as $private and $protected.
const Account = OOP
.class("Account")
.privateProperties({ password: "" })
.protectedProperties({ balance: 0 })
.methods({
authenticate(password) { return this.$private.password === password; },
deposit(amount) { this.$protected.balance += amount; }
})
.done();They are intentionally a JavaScript convention, not a security boundary. They do not appear in Object.keys() or JSON output.
Abstract classes and interfaces
.abstract() prevents direct construction but permits subclasses. Interfaces are lightweight runtime method contracts.
const Serializable = OOP.interface("Serializable", ["serialize"]);
const Record = OOP.class("Record").abstract().done();
const User = OOP
.class("User")
.inheritsFrom(Record)
.implements(Serializable)
.methods({ serialize() { return JSON.stringify(this); } })
.done();API
| Method | Purpose |
| --- | --- |
| .inheritsFrom(Class) | Inherit from another EasyOOP class. |
| .properties(values) | Add public instance defaults or validated properties. |
| .constructor(fn) | Set an instance constructor. |
| .methods(values) | Add prototype methods. |
| .staticProperties(values) / .staticMethods(values) | Add static members. |
| .getters(values) / .setters(values) | Add accessors. |
| .privateProperties(values) / .protectedProperties(values) | Add scoped, non-enumerable stores. |
| .uses(mixin) | Add a mixin created by OOP.mixin(). |
| .implements(interface) | Enforce methods from OOP.interface(). |
| .abstract() | Make a class non-instantiable directly. |
| .done() | Finalize and return the class. |
Development
npm test
npm run check
npm run typecheck
npm run benchmark
npm run benchmark:features
npm run benchmark:memoryThe package has no runtime dependencies, does not use eval, and does not use proxies.
