TypeScript 能强制函数必须返回两种类型吗? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
iqoo
V2EX    程序员

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

  •  
  •   iqoo 2022-05-31 23:32:39 +08:00 3178 次点击
    这是一个创建于 1295 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    第 1 条附言    2022-06-01 10:12:46 +08:00

    大致是这样的功能:

    // 编译不通过 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
    AV1
        1
    AV1  
       2022-05-31 23:51:05 +08:00
    没懂你想问什么,定义函数的时候返回值类型直接写“string | number”还不能达到你的需求么?
    thinkershare
        2
    thinkershare  
       2022-05-31 23:55:56 +08:00
    @DOLLOR 他想让编译器给他检查流程, 就是这个函数的返回必须必须即有 string 也有 number, 我目前是没想到有什么方法, 因为这个需求本质也是一种类型运算, 需要编译器检测函数返回类型, 然后组合. 但是目前 TS 似乎没有那个类型本身可用进行这种特殊的类型约束, 因为这个约束类型 never 这种, 需要超越类型本身的信息, 做分支流程检测.
    jsq2627
        3
    jsq2627  
       2022-06-01 00:05:05 +08:00
    ZE3kr
        4
    ZE3kr  
       2022-06-01 00:07:46 +08:00
    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  
       2022-06-01 00:21:08 +08:00
    https://www.typescriptlang.org/docs/handbook/2/conditional-types.html 这篇文档似乎是近期更新的,专门讲解 conditional type
        6
    learningman  
       2022-06-01 00:48:00 +08:00 via Android
    你想要的是 overload
    learningman
    Rocketer
        7
    Rocketer  
       2022-06-01 00:55:40 +08:00 via iPhone
    我还是看不懂需求,一个输入返回一个值,这个返回值不可能既是数字又是字符串。

    如果输入不同返回不同,那不是单元测试要做的事吗?
    Opportunity
        8
    Opportunity  
       2022-06-01 01:01:34 +08:00   1
    你需要 tsd ,实例里就有你说的内容

    https://github.com/SamVerschueren/tsd#strict-type-assertions
    liuzhaowei55
        9
    liuzhaowei55  
       2022-06-01 01:01:58 +08:00 via iPhone
    题主可以自己拆解这个函数为两个子函数分别处理两个分支,然后在外部包装一层,判断入参应该走哪个分支,即拆分了逻辑又对响应数据类型做了保证。
    iosyyy
        10
    iosyyy  
       2022-06-01 01:17:05 +08:00
    楼主的意思是强制要求返回 number+string 吧上面感觉有点跑题
    我个人觉得还是分成两个函数解决好点 你可以做一个 map 映射一下然后分别调用
    vision1900
        11
    vision1900  
       2022-06-01 01:30:29 +08:00
    函数本身只是个过程,它在执行前不知道究竟哪些分支会被执行。如果一个函数即可能返回 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  
       2022-06-01 01:33:03 +08:00
    估计要的是泛型,也就是尖括号用法

    getStringOrNumber<string>('aString');
    getStringOrNumber<number>(1);
    shakukansp
        13
    shakukansp  
       2022-06-01 01:40:35 +08:00
    overload
    renhou
        14
    renhou  
       2022-06-01 07:50:05 +08:00
    可以的,函数的重载
    lneoi
        15
    lneoi  
       2022-06-01 09:15:10 +08:00
    听着像是重载,一种输入对应一种返回类型
    raykle
        16
    raykle  
       2022-06-01 09:48:54 +08:00
    OP 需求没描述清楚。

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

    type X = string | number
    getStringOrNumber<X>(params: X): X
    zingwu
        17
    zingwu  
       2022-06-01 10:08:25 +08:00
    重载吧
    zhuweiyou
        18
    zhuweiyou  
       2022-06-01 12:04:34 +08:00
    泛型
    jeffhong
        19
    jeffhong  
       2022-06-01 16:06:35 +08:00 via iPhone
    你需要 sum type ,大多数编程语言不支持。不过你可以用 product type 来模拟下。
    qbqbqbqb
        20
    qbqbqbqb  
       2022-06-02 11:35:41 +08:00
    @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  
       2022-06-02 11:58:16 +08:00
    这个需求在 TypeScript 里其实不好做。因为 ts 里有一种 literal type 的东西。比如你的例子里的 c 函数,如果不手动指定返回类型的话,你以为编译器推断出的类型是 string|number ,结果其实是"hello"|123 ,也是一种比 string|number 更窄的类型,那它该不该报错呢? 按照你的需求应该是不报错,但是按照 ts 的类型系统"hello"|123 和 number 都是 extends string|number ,并不好区分。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1107 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 23:24 PVG 07:24 LAX 15:24 JFK 18:24
    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