Skip to content

Support for opaque and nominal types in typescript via a transformation.

License

Notifications You must be signed in to change notification settings

ForbesLindesay/opaque-types

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

opaque-types

Support for opaque and nominal types in typescript via a transformation.

Build Status

Installation

yarn add opaque-types

Usage

Define a file with the extension .src.ts. e.g. types.src.ts

// @nominal
export type Longitude = number;
// @nominal
export type Latitude = number;

// @opaque
export type UserID = number;

// @nominal
// @expose
export type Email = string;
export const Email = {
  isValid(email: string): email is Email {
    return /.+\@.+/.test(email);
  },
};

Running opaque-types <dirname> will generate a file called types.ts (i.e. without the .src part), that exposes opaque/nominal types, along with an API for casting to and from them.

Usage:

import {Longitude, Latitude, UserID, Email} from './types';

const i = UserID.unsafeCast(100);
const x = Longitude.unsafeCast(10);
const y = Latitude.unsafeCast(5);

export function go(id: UserID, longitude: Longitude, latitude: Latitude) {}

go(i, x, y);
// errors: go(i, y, x);

// errors: const a: number = x;
// errors: const b: number = y;
const a: number = Longitude.extract(x);
const b: number = Longitude.extract(y);

// cast validates the value. It is only
// available if `isValid` is defined.
const email = Email.cast('forbes@example.com');
const str: string = email;
// errors: const e: Email = 'forbes@example.com';
function sendMessage(email: Email, body: string) {}
sendMessage(email, 'Hi person at ' + email);
  • @nominal marks the type as a "nominal" type. If you declare the same "nominal" type, with the same name, in multiple different files, they will be treated as the same type. This is useful if you want to create a library that exposes an API with types like "Email".
  • @opaque marks the type as an "opaque" type. Each declaration of an @opaque type is separate, and cannot be confused, even if they have the same name.
  • @expose exposes the underlying type. In the above example, you can use an Email in a location where a string is required, but you still cannot pass an arbitrary string to a method expecting an Email.

License

MIT

About

Support for opaque and nominal types in typescript via a transformation.

Resources

License

Stars

Watchers

Forks

Packages

No packages published