Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
tiny-types
Advanced tools
TinyTypes is an npm module that makes it easy for TypeScript and JavaScript projects to give domain meaning to primitive types. It also helps to avoid all sorts of bugs and makes your code easier to refactor. Learn more.
API documentation is available at jan-molak.github.io/tiny-types/.
To install the module from npm:
npm install --save tiny-types
An int on its own is just a scalar with no meaning. With an object, even a small one, you are giving both the compiler and the programmer additional information about what the value is and why it is being used.
To define a single-value TinyType
- extend from TinyTypeOf<T>()
:
import { TinyTypeOf } from 'tiny-types';
class FirstName extends TinyTypeOf<string>() {}
class LastName extends TinyTypeOf<string>() {}
class Age extends TinyTypeOf<number>() {}
Every tiny type defined this way has
a readonly property
value
of type T
, which you can use to access the wrapped primitive value. For example:
const firstName = new FirstName('Jan');
firstName.value === 'Jan';
Each tiny type object has an equals
method, which you can use to compare it by value:
const
name1 = new FirstName('Jan'),
name2 = new FirstName('Jan');
name1.equals(name2) === true;
An additional feature of tiny types is a built-in toString()
method:
const name = new FirstName('Jan');
name.toString() === 'FirstName(value=Jan)';
Which you can override if you want to:
class Timestamp extends TinyTypeOf<Date>() {
toString() {
return `Timestamp(value=${this.value.toISOString()})`;
}
}
const timestamp = new Timestamp(new Date());
timestampt.toString() === 'Timestamp(value=2018-03-12T00:30:00.000Z))'
If the tiny type you want to model has more than one value,
or you want to perform additional operations in the constructor,
extend from TinyType
directly:
import { TinyType } from 'tiny-types';
class Person extends TinyType {
constructor(public readonly firstName: FirstName,
public readonly lastName: LastName,
) {
super();
}
}
You can also mix and match both of the above definition styles:
import { TinyType, TinyTypeOf } from 'tiny-types';
class UserName extends TinyTypeOf<string>() {}
class Timestamp extends TinyTypeOf<Date>() {
toString() {
return `Timestamp(value=${this.value.toISOString()})`;
}
}
abstract class DomainEvent extends TinyTypeOf<Timestamp>() {}
class AccountCreated extends DomainEvent {
constructor(public readonly username: UserName, timestamp: Timestamp) {
super(timestamp);
}
}
const event = new AccountCreated(new UserName('jan-molak'), new Timestamp(new Date()));
Even such complex types still have both the equals
and toString
methods:
const
now = new Date(2018, 2, 12, 0, 30),
event1 = new AccountCreated(new UserName('jan-molak'), new Timestamp(now)),
event2 = new AccountCreated(new UserName('jan-molak'), new Timestamp(now));
event1.equals(event2) === true;
event1.toString() === 'AccountCreated(username=UserName(value=jan-molak), value=Timestamp(value=2018-03-12T00:30:00.000Z))'
Every TinyType defines
a toJSON()
method,
which returns a JSON representation of the object. This means that you can use TinyTypes
as Data Transfer Objects.
Single-value TinyTypes are serialised to the value itself:
import { TinyTypeOf } from 'tiny-types';
class FirstName extends TinyTypeOf<string>() {}
const firstName = new FirstName('Jan');
firstName.toJSON() === 'Jan'
Complex TinyTypes are serialised recursively:
import { TinyType, TinyTypeOf } from 'tiny-types';
class FirstName extends TinyTypeOf<string>() {}
class LastName extends TinyTypeOf<string>() {}
class Age extends TinyTypeOf<number>() {}
class Person extends TinyType {
constructor(
public readonly firstName: FirstName,
public readonly lastName: LastName,
public readonly age: Age,
) {
super();
}
}
const person = new Person(new FirstName('Bruce'), new LastName('Smith'), new Age(55));
person.toJSON() === { firstName: 'Bruce', lastName: 'Smith', age: 55 }
Although you could define standalone de-serialisers, I like to define them as static factory methods on the TinyTypes themselves:
import { TinyTypeOf } from 'tiny-types';
class FirstName extends TinyTypeOf<string>() {
static fromJSON = (v: string) => new FirstName(v);
}
const firstName = new FirstName('Jan'),
FirstName.fromJSON(firstName.toJSON()).equals(firstName) === true
When working with complex TinyTypes, you can use the (experimental) Serialised
interface
to reduce the likelihood of your custom fromJSON
method being incompatible with toJSON
:
import { TinyTypeOf, TinyType, Serialised } from 'tiny-types';
class EmployeeId extends TinyTypeOf<number>() {
static fromJSON = (id: number) => new EmployeeId(id);
}
class DepartmentId extends TinyTypeOf<string>() {
static fromJSON = (id: string) => new DepartmentId(id);
}
class Allocation extends TinyType {
static fromJSON = (o: Serialised<Allocation>) => new Allocation(
EmployeeId.fromJSON(o.employeeId as number),
DepartmentId.fromJSON(o.departmentId as string),
)
constructor(public readonly employeeId: EmployeeId, public readonly departmentId: DepartmentId) {
super();
}
}
This way de-serialising a complex type becomes trivial:
const allocation = new Allocation(new EmployeeId(1), new DepartmentId('engineering'));
const deserialised = Allocation.fromJSON({ departmentId: 'engineering', employeeId: 1 });
allocation.equals(deserialised) === true
Although Serialised
is by no means 100% foolproof as it's only limited to checking whether your input JSON has the same fields
as the object you're trying to de-serialise, it can at least help you to avoid errors caused by typos.
Do you find TinyTypes useful? Give it a star! ★
Found a bug? Need a feature? Raise an issue or submit a pull request.
Have feedback? Let me know on twitter: @JanMolak
TinyTypes library is licensed under the Apache-2.0 license.
- Copyright © 2018- Jan Molak
FAQs
A tiny library that brings Tiny Types to JavaScript and TypeScript
The npm package tiny-types receives a total of 9,458 weekly downloads. As such, tiny-types popularity was classified as popular.
We found that tiny-types demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.