楔子
typescript 針對 javascript 有進行型別的補強,在 functional programming 的 lib 中,有 fp-ts
可以使用,不過個人覺的它有點複雜變的不太好用,它的型別有點太多了,先了解它的東西應該就飽了,那今天來試試改用小刀水平的 javascript 吧。
說明
先要熟悉一下 arrow function 的 typescript 有點不易閱讀(官網也這樣說)
這是一個取第一個值的簡單函數
let fst: (a: any, b: any) => any = (a, b) => a
如果套上括號(弄個特殊的括號 [ ] ),應該就可以比較好懂這個格式了。
let fst: [(a: any, b: any) => any] = (a, b) => a
比較容易理解的還是用純 function 來寫
function fst(a: any, b: any): any {
return a
}
如果再套上 Generic types 的表達格式
function fst<T,U>(a: T, b: U): T {
return a
}
接下來開始改造 lib 升級到 typescript 先從小的東西開始,如果原來的 javascript
export function Box(x){
return {
x,
map: (f) => Box(f(x)),
fold: (f, g) => f(x),
chain: (f) => f(x),
inspect: () => `Box(${x})`
}
}
typescript 的概念就是幫 javascript + type (好像廢話),所以讓自已記住一個很重要的起手示,就是要寫 type & function 要定義缺失的 type (eg. 參數…)
// step 1. defined types
type BoxProps<T> = {
x: T
map(f: Function): BoxProps<T>
fold(f: Function, g: Function): T
chain(f: Function): T
inspect: () => String
}
// step 2. write function & fill missing types
export function Box<T>(x: T): BoxProps<T> {
return {
x,
map: (f) => Box(f(x)),
fold: (f, g) => f(x),
chain: (f) => f(x),
inspect: () => `Box(${x})`
}
}
補上完整的作業 code
type BoxProps<T> = {
x: T
map(f: Function): BoxProps<T>
fold(f: Function, g: Function): T
chain(f: Function): T
inspect: () => String
}
export function Box<T>(x: T): BoxProps<T> {
return {
x,
map: (f) => Box(f(x)),
fold: (f, g) => f(x),
chain: (f) => f(x),
inspect: () => `Box(${x})`
}
}
type RightProps<T> = {
x: T
map(f: Function): RightProps<T>
fold(f: Function, g: Function): T
chain(f: Function): T
inspect: () => String
// ap(y: RightProp<T>): RightProp<T>,
}
export function Right<T>(x: T): RightProps<T> {
return {
x,
chain: (f) => f(x),
map: (f) => Right(f(x)),
fold: (f, g) => f(x),
inspect: () => `Right(${x})`
// ap: other => other.map(x),
// traverse: (of, f) => f(x).map(Right),
}
}
type LeftProps<T> = {
x: T
map(f: Function): LeftProps<T>
fold(f: Function, g: Function): T
chain(f: Function): LeftProps<T>
ap(f: Function): LeftProps<T>
inspect: () => String
}
export function Left<T>(x: T): LeftProps<T> {
return {
x,
chain: (f) => Left(x),
ap: (other) => Left(x),
map: (f) => Left(x),
fold: (f, g) => f(x),
inspect: () => `Left(${x})`
// traverse: (of, f) => of(Left(x)),
}
}
export function fromNullable<T>(x: T): RightProps<T> | LeftProps<null> {
return x === null || x === undefined ? Left(null) : Right(x)
}
export function tryCatch(f: Function) {
try {
return Right(f())
} catch (e) {
return Left(e)
}
}
let a = fromNullable(null)
console.log(a.inspect())
let b = () => {
throw new Error('yoyo')
}
let c = tryCatch(b)
console.log(c.inspect())
let d = fromNullable(3).map((x) => x + 6)
console.log(d.inspect())
let e = Left(3).map((x) => x + 1)
console.log(e.inspect())
參考資料