Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ possible to define records using object descriptions:
var Point = Type({Point: {x: Number, y: Number}});
```

If your type only has one constructor, as is the case here, you can use `Type.Record` to define essentially the same thing without having to name the lone constructor:
```javascript
var Point = Type.Record({x: Number, y: Number});
```

### Instance methods

Furthermore it is possible to add instance methods. A Maybe type with a map
Expand Down Expand Up @@ -136,6 +141,18 @@ Alternatively records can be constructed in the same way as regular types.
var p = Point.Point(1, 1);
```

If you used the `Type.Record` syntax to declare the type, e.g.

```javascript
var Point = Type.Record({x: Number, y: Number});
```

then you construct an instance of the type using `.from({...})`:

```javascript
var p = Point.from({x: 1, y: 1});
```

### Switching on union types

Every created type has a `case` function available along with its value
Expand Down Expand Up @@ -279,6 +296,24 @@ var list = List.Cons(1, List.Cons(2, List.Cons(3, List.Nil())));
console.log(toString(list)); // => '1 : 2 : 3 : Nil'
```

### Newtypes

Newtypes are similar to type aliases except they cannot be used interchangeably with the type they are based on; they are a new, distinct type. You can create a newtype like so:

```javascript
var ID = Type.New(String);
```

Then construct an instance of it using `.from()`:
```javascript
var id = ID.from('2ialp7b4lu');
```

The wrapped value is accessible using `id.value`:
```javascript
var stringValue = id.value;
```

### Disabling type checking

Type checking can be disabled, for instance in production, by setting
Expand Down
29 changes: 29 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ describe('union type', function() {
assert.equal(p.x, 1);
assert.equal(p.y, 2);
});
it('can use Type.Record to create record types', function() {
var Point = Type.Record({x: Number, y: Number});
});
it('can create Type.Record values', function() {
var Point = Type.Record({x: Number, y: Number});
var p = Point.from({x: 1, y: 2});
assert.equal(p.x, 1);
assert.equal(p.y, 2);
});
it('can create values from arguments', function() {
var Point = Type({Point: {x: Number, y: Number}});
var p = Point.Point(1, 2);
Expand All @@ -97,6 +106,26 @@ describe('union type', function() {
assert.equal(p[1], undefined);
});
});
describe('newtypes', function() {
it('can create a newtype, wrap and unwrap a value', function() {
var Age = Type.New(Number);
var myAge = Age.from(35);
assert.equal(35, myAge.value);
});
it('cannot be substituted with its wrapped type', function() {
var Age = Type.New(Number);
var Person = Type.Record({
name: String,
age: Age
});
assert.throws(function() {
Person.from({
name: 'Jimmy',
age: 34
});
}, /wrong value/);
});
});
describe('type methods', function() {
it('can add instance methods', function() {
var Maybe = Type({Just: [T], Nothing: []});
Expand Down
18 changes: 18 additions & 0 deletions union-type.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,4 +127,22 @@ function Type(desc) {

Type.check = true;

// Simplified syntax for creating records
Type.Record = function (desc) {
const type = Type({
record: desc
})
type.from = type.recordOf
return type
}

// Newtypes -- types isomorphic to but distinct from another type
Type.New = function (wrappedType) {
const type = Type({
newType: { value: wrappedType }
})
type.from = value => type.newTypeOf({value})
return type
}

module.exports = Type;