天天看點

typescript函數式程式設計的一次實踐

前提:為了培養團隊的技術能力,拿了個小修改需求作為函數式程式設計的實踐機會。

需求:業務部門提出積分活動,當使用者達成任務時送積分。簡化邏輯,我們暫且認為逢5送5分,逢10送10分,其他送1分。

即達成任務1-4次時,每次送1分。第5次送5分,第10次送10分。

實作過程:

mkdir [項目路勁]

npm init --y

npm install typescript ts-node --save-dev

//測試用

npm install jasmine @types/jasmine --save-dev

建立檔案fpdemo.ts

為了實作函數式,先定義兩個幫助方法:

1)等價于if/else的either

2)等價于for循環的repeat

either的目的是傳入一個條件、左分支、右分支,根據條件決定執行左分支還是右分支。右分支還能嵌套執行either方法。

repeat代替for循環,目的是依次執行每個either方法。

全部代碼實作如下

export namespace fpdemo {
    //獎勵積分常量
    const FifthAward = 5;
    const TenthAward = 10;
    const OthersAward = 1;

    //第五次
    export const IsFiveTimes = (arg: number)=> arg % 5 === 0;
    //第十次
    export const IsTenTimes = (arg: number)=> arg % 10 === 0;

    type eitherFn = <U, T>(value: U) => () => T;

    //這裡使用函數重載,right可以是一個數值,也可以嵌套的either方法
    function either<U>(condition: (arg: U) => boolean, left: number, right: number): any
    function either<U>(condition: (arg: U) => boolean, left: number, right: eitherFn): any
    function either<U>(condition: (arg: U) => boolean, left: number, right: number|Function): any
    {
        return (value: U) => condition(value)? left : 
        typeof right === "number"? right : right(value);
    }

    //代替for循環
    function repeat(current: number, cap: number, fn: Function, total=0): any {
        total += fn(current);
        return current>=cap? total : repeat(++current, cap, fn, total);
    } 

    console.log(        
        //傳入數值,判斷獎勵的數量
        either(IsTenTimes, TenthAward, either(IsFiveTimes, FifthAward, OthersAward))(10)
    );

    //從1-10,累加獎勵
    console.log(repeat(1, 10, either(IsTenTimes, TenthAward, either(IsFiveTimes, FifthAward, OthersAward))));
}
           

ts-node fpdemo.ts

執行結果可以看到1-10次的累加總額。

說到這裡,可能有人會有疑問,費了這麼大的勁,就為了寫個for+if/else就能解決的問題。 傳統(junior)的寫法,會這麼做

let times = 10;
let totalAward = 0
for(let i=0; i<times; i++ )
{
    if(i%10 == 0)
    {
        totalAward += 10;
    }
    else if(i%5 == 0)
    {
        totalAward += 5;
    }
    else {
        totalAward += 1;
    }
}
           

依我的了解,fp的好處至少有兩點

1:可複用 - 代碼裡的每個function都可以單獨導出,并在他處複用

2:可測試 - 由于沒有外部依賴,函數都是幂等的,是以每個function都可以導出并單元測試

最後安裝jasmine, 進行單元測試

添加配置檔案jasmine.json

{
    "spec_files": ["**/*[sS]pec.ts"]
}
           
import * as demo from './fpdemo';

describe('five', function() {
    it('add', function() {
        let result = demo.fpdemo.IsFiveTimes(5);
        expect(result).toEqual(true);
    })
})