Skip to content

Commit

Permalink
Merge pull request #19 from davecoates/map
Browse files Browse the repository at this point in the history
Support for Map
  • Loading branch information
lukesneeringer committed Jul 27, 2016
2 parents 3b18c6a + d6b3a41 commit 3ce7f0e
Show file tree
Hide file tree
Showing 5 changed files with 374 additions and 8 deletions.
43 changes: 41 additions & 2 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Point({x: "1", y: "2"}) // => TypeError: Invalid value for "x" field:
```


Record types definitions may also be provided a default values for feilds for a convinence of use:
Record types definitions may also be provided a default values for feilds for a convenience of use:

```js
var Point = Record({x: Number(0), y: Number(0)})
Expand Down Expand Up @@ -182,7 +182,7 @@ Numbers([1, 2, 3, "4", "5"]) // => TypeError: Invalid value: "4" is not a number
Numbers([1, 2, 3]).push(null) // => TypeError: Invalid value: "null" is not a number
```

Typed lists can also be named for convinience:
Typed lists can also be named for convenience:

```js
var Strings = List(String, "Strings")
Expand Down Expand Up @@ -225,6 +225,45 @@ xs.toString() // => Typed.List(Number)([ 1, 2 ])

As you can see from example above original `ps` list was of `Point` records while mapped `xs` list is of numbers and that is refleced in the type of the list. Although given that JS is untyped language theer is no guarantee that mapping function will return values of the same type which makes things little more complex, result of such mapping will be list of union type of all types that mapping funciton produced (see types section for union types).

### Map

You can define a typed map by providing `Map` the type for the key and the type for the value:

```js
var {Map, Record} = require("typed-immutable")
var Product = Record({name: String}, "Product")

var Products = Map(Number, Product)

Products().toString() // ‘Typed.Map(Number, Product)({})’

Products([[1, {name: "Mapper 1000"}]]).toString()
//Typed.Map(Number, Product)({ 1: Product({ "name": "Mapper 1000" }) })
```

Typed maps may contain only entries with key and value that match the specified type:

```js

Products([[1, "Mapper 1000"]])
// => TypeError: Invalid value: Invalid data structure "Mapper 1000" was passed to Product

Products().set("P1", {name: "Mapper 1000"})
// TypeError: Invalid key: "P1" is not a number

// All keys in an object are strings, so this fails too:
Products({1: {name: "Mapper 1000"}}) // TypeError: Invalid key: "1" is not a number
```

Note the last example - all keys in an object are strings so if you instantiate a map from an object the type of your key must be a string (or something that handles strings).

As with other types Typed maps can also be named for convenience:

```js
var Products = Map(Number, Product, "Products")
Products([[1, {name: "Mapper 1000"}]]).toString()
// Products({ 1: Product({ "name": "Mapper 1000" }) })
```

### Types

Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export {Record} from "./record"
export {List} from "./list"
export {Map} from "./map"
export {Typed, typeOf, Type, Any, Union, Maybe} from "./typed"
2 changes: 1 addition & 1 deletion src/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ export const List = function(descriptor, label) {
const type = typeOf(descriptor)

if (type === Any) {
throw TypeError("Typed.List was passed an invalid type descriptor: ${descriptor}")
throw TypeError(`Typed.List was passed an invalid type descriptor: ${descriptor}`)
}

const ListType = function(value) {
Expand Down
20 changes: 15 additions & 5 deletions src/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,8 @@ export const Map = function(keyDescriptor, valueDescriptor, label) {
const type = new EntryType(keyType, valueType, label)

const MapType = function(value) {
const isThis = this instanceof MapType
const constructor = isThis ? this.constructor : MapType
const isMapType = this instanceof MapType
const constructor = isMapType ? this.constructor : MapType

if (value instanceof constructor) {
return value
Expand All @@ -262,9 +262,7 @@ export const Map = function(keyDescriptor, valueDescriptor, label) {
throw result
}

const isCall = isThis && construct.prototype === this

if (!isCall && isThis) {
if (isMapType && !this[$store]) {
this[$store] = result[$store]
this.size = result.size
} else {
Expand All @@ -273,6 +271,18 @@ export const Map = function(keyDescriptor, valueDescriptor, label) {

return this
}

MapType.of = (...keyValues) => {
return MapType().withMutations(map => {
for (var i = 0; i < keyValues.length; i += 2) {
if (i + 1 >= keyValues.length) {
throw new Error('Missing value for key: ' + keyValues[i]);
}
map.set(keyValues[i], keyValues[i + 1]);
}
});
}

MapType.prototype = Object.create(MapPrototype, {
constructor: {value: MapType},
[$type]: {value: type},
Expand Down
Loading

0 comments on commit 3ce7f0e

Please sign in to comment.