Last active
December 5, 2015 05:26
-
-
Save unscriptable/03f20da58766158f74c9 to your computer and use it in GitHub Desktop.
flow Cart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
/* @flow */ | |
// Cart items. | |
type SKU = string; | |
type Item = { | |
sku: SKU, | |
quantity: number | |
}; | |
type Items = Map<SKU, Item>; | |
// Cart states. In lieu of enums, these are constant instances. | |
class Empty {} | |
const empty = new Empty(); | |
class Loaded {} | |
const loaded = new Loaded(); | |
class Paid extends Loaded {} | |
const paid = new Paid(); | |
// Cart, parameterized by state and Maybe Items (null | Items). | |
class Cart<state: Empty | Loaded | Paid> { | |
constructor (state: Empty | Loaded | Paid, items: ?Items) { | |
this.items = items != null ? items : new Map(); | |
} | |
items: Items; | |
} | |
// Exported cart functions. | |
export const create | |
: () => Cart<Empty> | |
= () => new Cart(empty); | |
export const addItem | |
: (cart: Cart<Empty> | Cart<Loaded>, item: Item) => Cart<Loaded> | |
= (cart, item) => { | |
const items = cart.items; | |
if (items.has(item.sku)) { | |
throw new Error(`Item is already in cart: ${ item.sku }.`); | |
} | |
items.set(item.sku, item); | |
return new Cart(loaded, items); | |
}; | |
export const removeItem | |
: (cart: Cart<Loaded>, item: Item) => Cart<Loaded> | Cart<Empty> | |
= (cart, item) => { | |
const items = cart.items; | |
if (!items.has(item.sku)) { | |
throw new Error(`Item is not in cart: ${ item.sku }.`); | |
} | |
items.delete(item.sku); | |
return items.count === 0 | |
? new Cart(empty) | |
: new Cart(loaded, items); | |
}; | |
export const replaceItem | |
: (cart: Cart<Loaded>, item: Item) => Cart<Loaded> | |
= (cart, item) => { | |
const items = cart.items; | |
if (!items.has(item.sku)) { | |
throw new Error(`Item is not in cart: ${ item.sku }.`); | |
} | |
items.set(item.sku); | |
return new Cart(loaded, items); | |
}; | |
export const pay | |
: (cart: Cart<Loaded>) => Cart<Paid> | |
= (cart) => { | |
// do some payments stuff here | |
return new Cart(paid, cart.items); | |
}; | |
// Example code. | |
let cart = create(); | |
cart = addItem(cart, { sku: '123213', quantity: 2 }); | |
// this line should fail to type-check: | |
cart = removeItem(create(), { sku: '123213', quantity: 2 }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
/* @flow */ | |
/*:: | |
type SKU = string; | |
type Item = { | |
sku: SKU, | |
quantity: number | |
}; | |
type Items = Map<SKU, Item>; | |
*/ | |
class EmptyCart {} | |
class LoadedCart { | |
constructor (items/*: Items*/) { | |
this.getItems = function () { return items; }; | |
} | |
/*:: getItems: () => Items;*/ | |
} | |
class PaidCart extends LoadedCart {} | |
// type AnyCart = EmptyCart | LoadedCart | PaidCart; | |
export const create | |
/*: () => EmptyCart*/ | |
= () => new EmptyCart(); | |
export const extractItems | |
/*: (cart: LoadedCart) => Items*/ | |
= cart => cart.getItems(); | |
export const addItem | |
/*: (cart: EmptyCart | LoadedCart, item: Item) => LoadedCart*/ | |
= (cart, item) => { | |
const items = cart instanceof EmptyCart | |
? (new Map()/*: Items*/) | |
: cart.getItems(); | |
if (items.has(item.sku)) { | |
throw new Error(`Item is already in cart: ${ item.sku }.`); | |
} | |
items.set(item.sku, item); | |
return new LoadedCart(items); | |
}; | |
export const removeItem | |
/*: (cart: LoadedCart, item: Item) => LoadedCart | EmptyCart*/ | |
= (cart, item) => { | |
const items = cart.getItems(); | |
if (!items.has(item.sku)) { | |
throw new Error(`Item is not in cart: ${ item.sku }.`); | |
} | |
items.delete(item.sku); | |
return items.count === 0 | |
? new EmptyCart() | |
: new LoadedCart(items); | |
}; | |
export const replaceItem | |
/*: (cart: LoadedCart, item: Item) => LoadedCart | EmptyCart*/ | |
= (cart, item) => { | |
const items = cart.getItems(); | |
if (!items.has(item.sku)) { | |
throw new Error(`Item is not in cart: ${ item.sku }.`); | |
} | |
items.set(item.sku); | |
return new LoadedCart(items); | |
}; | |
export const pay | |
/*: (cart: LoadedCart) => PaidCart*/ | |
= (cart) => { | |
// do some payments stuff here | |
return new PaidCart(cart.getItems()); | |
}; | |
let cart = create(); | |
cart = addItem(cart, { sku: '123213', quantity: 2 }); | |
// this line should fail to type-check: | |
cart = removeItem(create(), { sku: '123213', quantity: 2 }); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
/* @flow */ | |
type SKU = string; | |
type Item = { | |
sku: SKU, | |
quantity: number | |
}; | |
type Items = Map<SKU, Item>; | |
class EmptyCart {} | |
class LoadedCart { | |
constructor (items: Items) { | |
this.getItems = function () { return items; }; | |
} | |
getItems: () => Items; | |
} | |
class PaidCart extends LoadedCart {} | |
// type AnyCart = EmptyCart | LoadedCart | PaidCart; | |
export const create | |
: () => EmptyCart | |
= () => new EmptyCart(); | |
export const extractItems | |
: (cart: LoadedCart) => Items | |
= cart => cart.getItems(); | |
export const addItem | |
: (cart: EmptyCart | LoadedCart, item: Item) => LoadedCart | |
= (cart, item) => { | |
const items = cart instanceof EmptyCart | |
? (new Map(): Items) | |
: cart.getItems(); | |
if (items.has(item.sku)) { | |
throw new Error(`Item is already in cart: ${ item.sku }.`); | |
} | |
items.set(item.sku, item); | |
return new LoadedCart(items); | |
}; | |
export const removeItem | |
: (cart: LoadedCart, item: Item) => LoadedCart | EmptyCart | |
= (cart, item) => { | |
const items = cart.getItems(); | |
if (!items.has(item.sku)) { | |
throw new Error(`Item is not in cart: ${ item.sku }.`); | |
} | |
items.delete(item.sku); | |
return items.count === 0 | |
? new EmptyCart() | |
: new LoadedCart(items); | |
}; | |
export const replaceItem | |
: (cart: LoadedCart, item: Item) => LoadedCart | EmptyCart | |
= (cart, item) => { | |
const items = cart.getItems(); | |
if (!items.has(item.sku)) { | |
throw new Error(`Item is not in cart: ${ item.sku }.`); | |
} | |
items.set(item.sku); | |
return new LoadedCart(items); | |
}; | |
export const pay | |
: (cart: LoadedCart) => PaidCart | |
= (cart) => { | |
// do some payments stuff here | |
return new PaidCart(cart.getItems()); | |
}; | |
let cart = create(); | |
cart = addItem(cart, { sku: '123213', quantity: 2 }); | |
// this line should fail to type-check: | |
cart = removeItem(create(), { sku: '123213', quantity: 2 }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Other indentation styles: