使用 ts 的最佳境界:化类型于无形 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhennann
V2EX    Node.js

使用 ts 的最佳境界:化类型于无形

  •  
  •   zhennann 2024-04-11 11:22:09 +08:00 2702 次点击
    这是一个创建于 596 天前的主题,其中的信息可能已经有所发展或是发生改变。

    使用 ts 的最佳境界:化类型于无形

    在项目中使用 ts 可以带来类型智能提示与校验的诸多好处。同时,为了减少类型标注,达到化类型于无形的效果,CabloyJS 引入了 ioc 和依赖查找的机制。在上一篇文章中,我们创建了一个业务模块 test-home ,并且采用依赖查找的机制演示了如何优雅的定义和使用资源,包括:Service 服务、Config 配置、国际化语言资源、Error 错误异常

    在实际的项目当中,经常会遇到跨模块访问资源的场景,那么,CabloyJS 的依赖查找机制是否仍然可以优雅的实现跨模块访问呢?让我们一睹为快

    模块化体系与任务说明

    CabloyJS 全栈框架的前后端均采用模块化体系。一个 CabloyJS 项目由多个业务模块组成,每个业务模块都可以包含与自身业务相关的资源,比如:Service 服务、Config 配置、国际化语言资源、Error 错误异常、中间件、定时任务、消息队列、系统启动项,等等

    在这里,我们创建一个新的业务模块 test-work ,在 test-work 中访问 test-home 提供的资源

    1. 新建业务模块

    cabloy api:create:module test-work 

    2. 新建 API

    通过一个命令同时创建一组文件:Route 、Controller 、Service

    cabloy api:create:controller work 

    3. 跨模块访问 Service 服务

    接下来,我们在刚才新建的 Service 当中,访问模块 test-home 的 Service 服务

    import { BeanBase, Local } from '@cabloy/core'; import { ScopeModule } from '../resource/this.js'; @Local() export class LocalWork extends BeanBase<ScopeModule> { async action({ user }) { + const scopeHome = this.getScope('test-home'); + return scopeHome.local.home.action({ user }); // return user; } } 
    1. 通过 getScope 方法获取模块 test-home 的 scope 对象
    2. 通过 scope 对象直接访问 Service 服务: home

    看一下动画演示,提供了完整的类型智能提示:

    cross-module-localbean.gif

    4. 跨模块访问 Config 配置

    访问模块 test-home 的 Config 配置

    import { BeanBase, Local } from '@cabloy/core'; import { ScopeModule } from '../resource/this.js'; @Local() export class LocalWork extends BeanBase<ScopeModule> { async action({ user }) { const scopeHome = this.getScope('test-home'); + const prompt = scopeHome.config.prompt; return scopeHome.local.home.action({ user }); // return user; } } 
    1. 直接通过 scopeHome 取得 config 中的 prompt 属性值

    看一下动画演示,提供了完整的类型智能提示:

    cross-module-config.gif

    5. 跨模块访问国际化语言资源

    访问模块 test-home 的国际化语言资源

    import { BeanBase, Local } from '@cabloy/core'; import { ScopeModule } from '../resource/this.js'; @Local() export class LocalWork extends BeanBase<ScopeModule> { async action({ user }) { const scopeHome = this.getScope('test-home'); + const message = scopeHome.locale.HelloWorld(); + const message1 = scopeHome.locale.HelloWorld.locale('en-us'); + const message2 = scopeHome.locale.HelloWorld.locale('zh-cn'); return scopeHome.local.home.action({ user }); // return user; } } 

    看一下动画演示,提供了完整的类型智能提示:

    cross-module-locale-small.gif

    6. 跨模块访问 Error 错误异常

    抛出模块 test-home 提供的 Error 错误异常

    import { BeanBase, Local } from '@cabloy/core'; import { ScopeModule } from '../resource/this.js'; @Local() export class LocalWork extends BeanBase<ScopeModule> { async action({ user }) { const scopeHome = this.getScope('test-home'); + scopeHome.error.Error001.throw(); return scopeHome.local.home.action({ user }); // return user; } } 
    1. 直接通过 scopeHome 抛出错误异常 Error001

    看一下动画演示,提供了完整的类型智能提示:

    cross-module-error.gif

    后记

    CabloyJS 采用 ioc 和依赖查找的机制,让 ts 的使用达到了化类型于无形的最佳境界,从而让我们的代码保持优雅和简洁,进而也能显著提升开发效率,保证代码质量

    欲了解更多,请关注每晚 8 点 B 站直播:濮水代码

    13 条回复    2024-04-12 10:19:21 +08:00
    calmbinweijin
        1
    calmbinweijin  
       2024-04-11 12:50:37 +08:00
    没说清楚,但是感觉有点意思
    arfaWong
        2
    arfaWong  
       2024-04-11 13:44:17 +08:00
    看标题进来还以为 anyscript 呢,哈哈哈哈
    zhennann
        3
    zhennann  
    OP
       2024-04-11 14:52:54 +08:00
    @arfaWong 所以写这篇文章,必须得配动图,要不还以为又回到了 anyscript
    encro
        4
    encro  
       2024-04-11 15:26:39 +08:00
    难道这个框架是我这个问题的答案? t/1026896#reply7
    encro
        5
    encro  
       2024-04-11 15:28:47 +08:00
    不过你这写法,让跨模块失去了意义呢。
    zhennann
        6
    zhennann  
    OP
       2024-04-11 15:41:53 +08:00
    @encro 这句话不理解
    zhennann
        7
    zhennann  
    OP
       2024-04-11 15:42:37 +08:00
    @encro 跨模块,不就是资源按模块隔离,然后再跨模块访问吗?
    encro
        8
    encro  
       2024-04-11 15:53:36 +08:00
    @zhennann

    模块化的意义在于只通过模块的接口去访问,
    如果可以任意访问模块的方法或者数据,就失去模块化黑箱的意义了吧,没有达到解耦的目的。
    我通过例子是没看出这种模块化的意义。
    当然可能是因为 config 和 error 都属于 base 模块。
    zhennann
        9
    zhennann  
    OP
       2024-04-11 16:17:20 +08:00
    @encro

    如果只通过接口访问模块的资源,更好的方案应该是微服务
    在一个大型项目中,模块的资源不只有 api 接口,config 和 error 资源也可以按照模块隔离,这样可以让与某个业务相关的资源代码充分自治
    encro
        10
    encro  
       2024-04-11 16:42:16 +08:00
    @zhennann

    在一个大型项目中,模块的资源不只有 api 接口,config 和 error 资源也可以按照模块隔离,这样可以让与某个业务相关的资源代码充分自治


    是这样没错,所以这样直接访问,就又变成了不自治了,不是吗?
    zhennann
        11
    zhennann  
    OP
       2024-04-11 21:59:35 +08:00
    @encro 总感觉你要的是微服务架构,而不是模块化架构
    zhennann
        12
    zhennann  
    OP
       2024-04-12 09:24:09 +08:00
    @encro
    在模块化架构中也可以实现你所说的“黑箱隔离”。其他模块需要什么 config 资源,在本模块通过 Service 服务包装提供即可
    encro
        13
    encro  
       2024-04-12 10:19:21 +08:00
    @zhennann

    是的,在架构上,尽量向微服务靠拢,减少模块交互。
    config ,location, error,log ,queue 这些都是属于框架级别的可以共用。
    user,auth,storage,payment 之类属于应用级别的应该尽量隔离。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     859 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 32ms UTC 22:05 PVG 06:05 LAX 14:05 JFK 17:05
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86