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"]
}

新建文件fpdemo.spec.ts,代码如下

import * as demo from './fpdemo';

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

修改package.json, 加入测试脚本
"scripts": {
"test": "ts-node node_modules/jasmine/bin/jasmine --config=jasmine.json"
},

运行npm run test,可以看到测试结果

posted @ 2021-10-18 10:34  老胡Andy  阅读(229)  评论(0编辑  收藏  举报