ts-roids

ts-roids

100+ types and decorators to bullet proof TypeScript even more.

CI @latest npm downloads Socket Badge


Installation

npm

npm i ts-roids

pnpm

pnpm i ts-roids

If you're only using types, you can install it as a devDependency. And if you're using decorators, set this.

{
"compilerOptions": {
// ...
"experimentalDecorators": true
}
}

Requires TypesScript v5.0+

Documentation

Checkout the full API reference for all usage examples with details.

Types

Decorators

Basic Usage

Finalize and freeze objects

import type { Optional, NewType, MaybeUndefined } from 'ts-roids';
import { Final, Frozen } from 'ts-roids';

type Bar = NewType<'Bar', string>;
type Baz = NewType<'Baz', string>;
type Secret = NewType<'Secret', string>;

abstract class BaseFoo<T> {
abstract requestFoo(secret: Secret, baz: Baz): Optional<T>;
}

@Final
@Frozen
class Foo<T> extends BaseFoo<T> {
readonly foo: T;
bar: Optional<Bar>;

constructor(foo: T, bar?: MaybeUndefined<Bar>) {
super();
this.foo = foo;
this.bar = bar ?? null;
}


requestFoo(secret: Secret, baz: Baz): Optional<T> {
// A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value
if (
secret.concat().toLowerCase() === '123' &&
baz.concat().toLowerCase() === 'baz' &&
this.bar !== null
) {
return this.foo;
}

return null; // So you have to explicitly return null here.
}
}

class SubFoo extends Foo<string> {
constructor(foo: string) {
super(foo);
}
}

// No problem with instantiation
const foo = new Foo<string>('foo');

// Since the object is final:

// The line below will cause a TypeError: Cannot inherit from the final class Foo
const _ = new SubFoo('subFoo');

// Since the object is frozen:

// The line below will cause a TypeError: Cannot add property 'requestFoo', object is not extensible
foo.requestFoo = () => {
return 'not foo';
};

// The line below will cause a TypeError: Cannot assign to read only property 'bar'
foo.bar = 'not bar' as Bar;

The TypeScript team has not yet introduced a built-in final modifier yet, check this, this and many other requests. Although they introduced override in v4.3 .

Decorators like @Final provide a limited way to emulate final behavior, these are merely band-aids for now, until TS officially supports a true final modifier.

You can also seal an object btw.

@Sealed
class Person {
constructor(name: string, age?: number) {}
}

const john = new Person('John', 30);

// Existing properties can still be modified
john.age = 31; // No Errors

// Existing properties cannot be re-configured nor deleted

(john as any).email = 'john@doe.com'; // TypeError: Cannot add property email,
// object is not extensible

delete john.age; // TypeError: Cannot delete property 'age'

Changelog

See releases.

License

GPL-3