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

TypeScript 能强制函数必须返回两种类型吗?

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

    比如 type X = string | number ,如果定义函数返回类型是 X ,那么只要是 string 或 number 其中一个就可以。

    如果想让函数两种类型都必须有返回(不同的分支返回不同的类型),是否有其他办法?

    第 1 条附言  ·  292 天前

    大致是这样的功能:

    // 编译不通过
    function a() : string && number {
      return 123
    }
    
    // 编译不通过
    function b() : string && number {
      return 'hello'
    }
    
    // 编译通过
    function c() : string && number {
      if (...) {
        return 123
      }
      return 'hello'
    }
    
    21 条回复    2022-06-02 11:58:16 +08:00
    DOLLOR
        1
    DOLLOR  
       293 天前
    没懂你想问什么,定义函数的时候返回值类型直接写“string | number”还不能达到你的需求么?
    thinkershare
        2
    thinkershare  
       293 天前
    @DOLLOR 他想让编译器给他检查流程, 就是这个函数的返回必须必须即有 string 也有 number, 我目前是没想到有什么方法, 因为这个需求本质也是一种类型运算, 需要编译器检测函数返回类型, 然后组合. 但是目前 TS 似乎没有那个类型本身可用进行这种特殊的类型约束, 因为这个约束类型 never 这种, 需要超越类型本身的信息, 做分支流程检测.
    ZE3kr
        4
    ZE3kr  
       293 天前
    OP 想问的是如何保证这个函数有可能返回每一种类型

    但问题是根据定义,只返回 string 或 number 中的一种,这个函数的返回值类型也属于 X 。不如约定一个自己的类型 Y ( Y 是一个 Function/Class ),这样只要返回的是 Y 你就知道一定是都有返回了。

    Function/Method subtyping is always contravariant in its argument

    ProvideMore do(Take less);
    jsq2627
        5
    jsq2627  
       293 天前
    https://www.typescriptlang.org/docs/handbook/2/conditional-types.html 这篇文档似乎是近期更新的,专门讲解 conditional type
    learningman
        6
    learningman  
       293 天前 via Android
    你想要的是 overload
    Rocketer
        7
    Rocketer  
       293 天前 via iPhone
    我还是看不懂需求,一个输入返回一个值,这个返回值不可能既是数字又是字符串。

    如果输入不同返回不同,那不是单元测试要做的事吗?
    Opportunity
        8
    Opportunity  
       293 天前   ❤️ 1
    你需要 tsd ,实例里就有你说的内容

    https://github.com/SamVerschueren/tsd#strict-type-assertions
    liuzhaowei55
        9
    liuzhaowei55  
       293 天前 via iPhone
    题主可以自己拆解这个函数为两个子函数分别处理两个分支,然后在外部包装一层,判断入参应该走哪个分支,即拆分了逻辑又对响应数据类型做了保证。
    iosyyy
        10
    iosyyy  
       293 天前
    楼主的意思是强制要求返回 number+string 吧上面感觉有点跑题
    我个人觉得还是分成两个函数解决好点 你可以做一个 map 映射一下然后分别调用
    vision1900
        11
    vision1900  
       293 天前
    函数本身只是个过程,它在执行前不知道究竟哪些分支会被执行。如果一个函数即可能返回 string 也可能返回 number ,而且具体返回 string 还是 number 的判断是在函数内,那么他就只能返回 string | number.

    这个问题本身无解。

    假设原来的 function 是这样:

    ```typescript
    // 获取日本人的出生年(尽可能用国号纪年)
    function getBirthYear(age: number) {
    const year = (new Date()).getFullYear() - age
    if (year > 2019) {
    return `令和${year - 2019}年`
    } else if (year > 1989) {
    return `平成${year - 1989}年`
    } else if (year > 1926) {
    return `昭和${year - 1926}年`
    } else {
    return year
    }
    }

    console.log(getBirthYear(100)) // 1922
    console.log(getBirthYear(24)) // "平成 9 年"
    ```
    muzuiget
        12
    muzuiget  
       293 天前
    估计要的是泛型,也就是尖括号用法

    getStringOrNumber<string>('aString');
    getStringOrNumber<number>(1);
    shakukansp
        13
    shakukansp  
       293 天前
    overload
    renhou
        14
    renhou  
       292 天前
    可以的,函数的重载
    lneoi
        15
    lneoi  
       292 天前
    听着像是重载,一种输入对应一种返回类型
    raykle
        16
    raykle  
       292 天前
    OP 需求没描述清楚。

    @muzuiget 乍一看我也觉得是泛型

    type X = string | number
    getStringOrNumber<X>(params: X): X
    zingwu
        17
    zingwu  
       292 天前
    重载吧
    zhuweiyou
        18
    zhuweiyou  
       292 天前
    泛型
    jeffhong
        19
    jeffhong  
       292 天前 via iPhone
    你需要 sum type ,大多数编程语言不支持。不过你可以用 product type 来模拟下。
    qbqbqbqb
        20
    qbqbqbqb  
       291 天前
    @raykle OP 需求应该是想对 union type 返回值做反向的 exhaustiveness check.

    正向的 exhaustiveness check 主要是针对这种值的读取的,比如说有些语言的 switch-case 或模式匹配如果缺了几个 case 又没有显式写 default case 的话编译器就会产生 warning 甚至 error 这样。一般不针对赋值、返回值等写入操作。

    而 OP 希望对函数返回值的写入也可以进行这种 check 。就比如说你有一个类型
    type X = string | number
    然后定义一个函数
    getStringOrNumber(): X
    这时如果函数体内只有 return string 的语句而没有 return number 的语句, [也就是说这个 X 类型里有几种情况没有用到,可以改成 getStringOrNumber(): string 也不出错] ,OP 希望遇到这种情况编译器可以提供 warning 或者 error 。
    qbqbqbqb
        21
    qbqbqbqb  
       291 天前
    这个需求在 TypeScript 里其实不好做。因为 ts 里有一种 literal type 的东西。比如你的例子里的 c 函数,如果不手动指定返回类型的话,你以为编译器推断出的类型是 string|number ,结果其实是"hello"|123 ,也是一种比 string|number 更窄的类型,那它该不该报错呢? 按照你的需求应该是不报错,但是按照 ts 的类型系统"hello"|123 和 number 都是 extends string|number ,并不好区分。
    关于   ·   帮助文档   ·   博客   ·   nftychat   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   实用小工具   ·   1060 人在线   最高记录 5556   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 41ms · UTC 19:47 · PVG 03:47 · LAX 12:47 · JFK 15:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.