V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zhbhun
V2EX  ›  TypeScript

TypeScript 类型推导真强大。

  •  2
     
  •   zhbhun · 40 天前 · 1461 次点击
    这是一个创建于 40 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在学习开发客户端相关的功能,发现 Kotlin 和 Swift 要实现泛化的高阶函数不太容易。比如我要实现一个高阶函数,需要将传入的一个 async 函数转为串行执行的函数,必须等待前一个任务完成后才能开始下一个。使用 TS 可以这么做:

    function sequentialize<T extends (...args: any[]) => Promise<any>>(
      asyncFn: T
    ): (...args: Parameters<T>) => ReturnType<T> {
      let queue: Promise<void> = Promise.resolve(); // 初始化队列
      return function (...args: Parameters<T>): ReturnType<T> {
        const result = queue.then(() => asyncFn(...args)); // 将异步任务添加到队列中
        queue = result.catch(() => {}); //捕获错误,防止队列中
        return result as ReturnType<T>; //确保返回类型与原始函数一致
      };
    }
    
    async function plus(a: number, b: number): Promise<number> {
      await new Promise<void>((resolve) => {
        setTimeout(() => {
          resolve();
          console.log(performance.now(), a, b);
        }, 1000);
      });
      return a + b;
    }
    
    const sequentializePlus = sequentialize(plus);
    
    

    但这在 Swift 和 Kotlin 里不太好处理,它们没法传入动态的函数,并包装后返回同类型的函数。想问下,如果像 Swift 和 Kotlin 这样的强类型语言要实现这样的语法,是否会存在什么限制?是否是因为 TS 编译后的 JS 是动态类型的,才支持这种类型推导(运行不会出问题),而 Swift 和 Kotlin 无法做到?

    13 条回复    2024-10-19 19:08:08 +08:00
    jy02534655
        1
    jy02534655  
       40 天前
    这个应该和 TypeScript 关系不大吧,js 特性,js 是弱语言类型
    maichael
        2
    maichael  
       40 天前
    JS 能这样实现,不是因为它强大,而恰恰是因为它够“弱”才能这么做;跟 Typescript 就更没啥直接关系了。
    zhbhun
        3
    zhbhun  
    OP
       40 天前
    @jy02534655 是的,js 支持这种高阶函数的封装。但是 TS 加了类型后,也仍然支持,并且可以在编译时检查函数类型。所以有这个疑问,是否是因为像 JS 运行时支持这种写法才行,而 Swift 和 Kotlin 无法做到。
    wlingxiao
        4
    wlingxiao  
       40 天前 via Android
    kotlin 了解的不多不确定能能不能做到,但是同为 jvm 上的语言 scala 可以做到,这些都是编译器的魔法,和运行时没关系。
    换个思路想,js 代码也是可以跑在 jvm 上的。
    dejavuwind
        5
    dejavuwind  
       40 天前
    Kotlin 应该也能实现吧? https://book.kotlincn.net/text/lambdas.html
    类似于 Java 的 Functional Interface ?
    zhbhun
        6
    zhbhun  
    OP
       40 天前
    @wlingxiao @dejavuwind 尝试用 Kotlin 写了下,没搞出来,让 ChatGPT 也说不行。主要是卡在 sequentialize 传入的函数无法是动态的,没有像 TS 提供 Parameters 和 ReturnType 来推导传入的函数类型,只能固定参数类型和返回值,这样就违背了泛化的初衷
    hronro
        7
    hronro  
       40 天前
    你这有点题不对文, [类型推导] 指的是不用写类型标注,编译器就能自动推导出变量的类型,TS 在这方面被 OCaml 秒成渣渣。
    至于你文中说的这种情况,只要是类型系统强大一点或者支持函数为一等公民的都能实现,和强弱类型没有任何关系,像 Rust 这种更偏底层的语言也能实现你之前提到的特性。
    zhbhun
        8
    zhbhun  
    OP
       40 天前
    @hronro 感谢!我去学习下 OCaml 和 Rust 。标题确实没拟好,想改的发现改不了了😭。
    zhbhun
        9
    zhbhun  
    OP
       40 天前
    @hronro 试了下 rust ,确实支持,看来还是跟语言设计有关系。

    ```rust
    fn with_logging<F, R>(args: F) -> R
    where
    F: FnOnce() -> R, // 接受一个闭包或函数,返回类型为 R
    {
    println!("执行函数之前的日志...");
    let result = args(); // 执行传入的闭包
    println!("执行函数之后的日志...");
    result // 返回传入闭包的返回值
    }

    fn main() {
    // 无参数函数
    let no_args_task = || {
    println!("无参数任务执行中...");
    42
    };

    // 单个参数函数
    let single_arg_task = |x: i32| -> i32 {
    println!("单个参数任务,参数为:{}", x);
    x * 2
    };

    // 多个参数函数,通过闭包包装来适配
    let multiple_args_task = |x: i32, y: i32| -> i32 {
    println!("多个参数任务,参数为:{}, {}", x, y);
    x + y
    };

    // 调用高阶函数
    let result1 = with_logging(no_args_task);
    let result2 = with_logging(|| single_arg_task(21));
    let result3 = with_logging(|| multiple_args_task(5, 10));

    println!("无参数任务返回值:{}", result1);
    println!("单个参数任务返回值:{}", result2);
    println!("多个参数任务返回值:{}", result3);

    // 最终输出
    // 执行函数之前的日志...
    // 无参数任务执行中...
    // 执行函数之后的日志...
    // 执行函数之前的日志...
    // 单个参数任务,参数为:21
    // 执行函数之后的日志...
    // 执行函数之前的日志...
    // 多个参数任务,参数为:5, 10
    // 执行函数之后的日志...
    // 无参数任务返回值:42
    // 单个参数任务返回值:42
    // 多个参数任务返回值:15
    ```
    hguandl
        10
    hguandl  
       40 天前
    zhbhun
        11
    zhbhun  
    OP
       40 天前
    @hguandl 真的可以耶,感谢大佬!
    zhbhun
        12
    zhbhun  
    OP
       40 天前
    有哪位大佬知道 Kotlin 是否可以实现的吗?
    SoloCompany
        13
    SoloCompany  
       39 天前
    有类型支持是好事
    但类型体操玩过头了就是给自己找不痛快
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   4804 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 05:38 · PVG 13:38 · LAX 21:38 · JFK 00:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.