typeomatica
v0.3.57
Published
type logic against javascript metaprogramming
Maintainers
Readme
TypeØmatica
This package is a part of mnemonica project.
Strict Runtime Type Checker for JavaScript Objects
TypeØmatica uses JavaScript Proxies to enforce type safety at runtime, exactly as TypeScript expects at compile time. Once a property is assigned a value, its type is locked and cannot be changed.
Quick Start
import { BaseClass } from 'typeomatica';
class User extends BaseClass {
name: string = 'default';
age: number = 0;
}
const user = new User();
// ✓ Valid assignments
user.name = 'John';
user.age = 25;
// ✗ Runtime error (even if TypeScript is bypassed with @ts-ignore)
user.age = '25'; // TypeError: Type MismatchTable of Contents
- What is TypeØmatica?
- Installation
- Core Concepts
- API Reference
- Usage Patterns
- Type Examples
- Working with Wrapped Values
- Error Reference
- Integration with Mnemonica
What is TypeØmatica?
TypeØmatica provides strict runtime type checking for JavaScript objects using Proxy-based interception. It ensures that once a property is initialized with a type, that type cannot be violated at runtime.
Key Features:
- Runtime type enforcement (complements TypeScript's compile-time checks)
- Proxy-based property interception
- Type locking after initial assignment
- Prevents prototype mutation, property redefinition, and deletion
Installation
npm install typeomaticaCore Concepts
How It Works
TypeØmatica wraps objects with JavaScript Proxies that intercept:
get- Property readsset- Property writes (with type validation)setPrototypeOf- Blocks prototype changesdefineProperty- Blocks property redefinitiondeleteProperty- Blocks property deletion
Type Categories
| Category | Types | Behavior |
|----------|-------|----------|
| primitives | string, number, boolean, bigint, symbol, undefined | Type-locked accessors |
| nullish | null | Only null allowed |
| objects | object, arrays, dates | Same constructor type required |
| functions | methods | Restricted on data types |
API Reference
BaseClass
The primary class for strict-type objects.
import { BaseClass } from 'typeomatica';
class MyClass extends BaseClass {
field: string = 'value';
constructor() {
super();
}
}BasePrototype
Functional equivalent of BaseClass.
import { BasePrototype } from 'typeomatica';
const Base = BasePrototype({ initialProp: 123 });
class MyClass extends Base { }@Strict() Decorator
Apply strict typing without extending BaseClass.
import { Strict } from 'typeomatica';
@Strict({ deep: true })
class MyClass {
field: number = 0;
}Decorator Arguments:
- First argument: Base prototype or options object
- Second argument: Options object
Options Interface
interface TypeomaticaOptions {
strictAccessCheck?: boolean; // default: false
}Options:
strictAccessCheck: true- Enables strict receiver checking (throwsACCESS_DENIEDerror when property is accessed from wrong context)deep: true- Enable recursive property checking (when using BasePrototype with initial values)
Usage with Options
// With BaseClass - strict access checking enabled
class SecureData extends BaseClass {
secret: string = '';
constructor() {
super(undefined, { strictAccessCheck: true });
}
}
// With BasePrototype - strict access checking enabled
const SecureBase = BasePrototype({ data: '' }, { strictAccessCheck: true });
class User extends SecureBase {
name: string = '';
}
// With @Strict decorator - strict access checking enabled
@Strict(undefined, { strictAccessCheck: true })
class Product {
price: number = 0;
}Symbol Exports
import {
SymbolTypeomaticaProxyReference, // Access proxy internals
SymbolInitialValue // Access original values
} from 'typeomatica';Usage Patterns
Pattern 1: Extending BaseClass
import { BaseClass } from 'typeomatica';
class User extends BaseClass {
name: string = '';
age: number = 0;
active: boolean = true;
}
const user = new User();
user.name = 'John'; // ✓ Works
user.age = 25; // ✓ Works
// @ts-ignore
user.age = '25'; // ✗ TypeError: Type MismatchPattern 2: @Strict Decorator
import { Strict } from 'typeomatica';
@Strict({ deep: true })
class Product {
id: number = 0;
title: string = '';
price: number = 0;
}
const product = new Product();
product.price = 29.99; // ✓ Works
// @ts-ignore
product.price = '$29.99'; // ✗ TypeError: Type MismatchPattern 3: BaseClass as Prototype
import { BaseClass } from 'typeomatica';
class UserData {
name: string = 'default';
age: number = 0;
}
// Inject type checking into prototype chain
Object.setPrototypeOf(UserData.prototype, new BaseClass({ deep: true }));
const user = new UserData();
user.name = 'John'; // ✓ Works
// @ts-ignore
user.name = 123; // ✗ TypeError: Type MismatchType Examples
Primitives
import { BaseClass } from 'typeomatica';
class Primitives extends BaseClass {
str: string = 'hello';
num: number = 42;
bool: boolean = true;
bigint: bigint = BigInt(100);
}
const p = new Primitives();
p.str = 'world'; // ✓ Works
p.num = 100; // ✓ Works
// @ts-ignore
p.str = 123; // ✗ TypeError: Type MismatchNull and Undefined
class Nullable extends BaseClass {
nullValue: null = null;
undefinedValue: undefined = undefined;
}
const n = new Nullable();
n.nullValue = null; // ✓ Works
// @ts-ignore
n.nullValue = undefined; // ✗ TypeError: Type MismatchObjects
class WithObject extends BaseClass {
data: object = {};
list: number[] = [];
}
const w = new WithObject();
w.data = { a: 1 }; // ✓ Works
w.list = [1, 2, 3]; // ✓ Works
// @ts-ignore
w.data = 123; // ✗ TypeError: Type Mismatch
// @ts-ignore
w.data = new Set(); // ✗ TypeError: Type Mismatch (Set !== Object)Working with Wrapped Values
TypeØmatica wraps primitives to enforce type safety. Use valueOf() for operations.
Numeric Operations
class Calc extends BaseClass {
count: number = 10;
}
const calc = new Calc();
// ✗ Direct arithmetic throws
const result = calc.count + 5; // ReferenceError: Value Access Denied
// ✓ Use valueOf()
const result = calc.count.valueOf() + 5; // 15
const sum = 3 + +calc.count; // 13String Operations
class Text extends BaseClass {
message: string = 'hello';
}
const text = new Text();
text.message.valueOf().toUpperCase(); // 'HELLO'
text.message.valueOf().length; // 5Error Reference
| Error Message | Error Type | When Thrown |
|---------------|------------|-------------|
| Type Mismatch | TypeError | Wrong type assigned to property |
| Value Access Denied | ReferenceError | Property accessed from wrong context (only when strictAccessCheck: true) |
| Attempt to Access to Undefined Prop | Error | Reading non-existent property |
| Functions are Restricted | TypeError | Function assigned to data property |
| Re-Assirnment is Forbidden | TypeError | Modifying read-only custom field |
| Setting prototype is not allowed | Error | Calling Object.setPrototypeOf() |
| Defining new Properties is not allowed | Error | Calling Object.defineProperty() |
| Properties Deletion is not allowed | Error | Calling delete on property |
Integration with Mnemonica
TypeØmatica integrates seamlessly with mnemonica for combined prototype inheritance and runtime type safety.
import { decorate } from 'mnemonica';
import { BaseClass, Strict } from 'typeomatica';
@decorate()
@Strict()
class Entity extends BaseClass {
id: string = '';
createdAt: Date = new Date();
}
// Works with mnemonica's inheritance system
const User = Entity.define('User', function(this: { email: string }) {
this.email = '';
});
const user = new User();
// @ts-ignore
user.email = 123; // ✗ TypeError: Type MismatchDecorator Order Matters:
@Strict()must come AFTER@decorate()(inner decorator)- Decorators apply bottom-to-top
For complete integration documentation, see mnemonica's TypeØmatica guide.
License
MIT
Copyright (c) 2019-2024 https://github.com/wentout
