请教一个 typescript 的类型问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
kernel
V2EX    Javascript

请教一个 typescript 的类型问题

  •  
  •   kernel 2018-10-01 19:33:04 +08:00 6467 次点击
    这是一个创建于 2566 天前的主题,其中的信息可能已经有所发展或是发生改变。
    export {} type F = ((a: string) => void) | ((b: boolean) => void) let f: F = (a: string) => {} f('foo') function f2 (f: F) { f('foo') ^^^^^ } 

    为什么光标处会出现这个错误呢?

    [ts] Cannot invoke an expression whose type lacks a call signature. Type 'F' has no compatible call signatures.

    PS. 唉头一次写 typescript 程序,碰到无数问题。typescript 要在本来无类型的 js 上面加类型搞出来的东西貌似比 java 的类型系统坑多(当然也灵活的多)

    16 条回复    2018-10-03 13:47:06 +08:00
    kernel
        1
    kernel  
    OP
       2018-10-01 19:53:44 +08:00
    额发现这里应该用&,才能得到正确的 overload 效果
    hst001
        2
    hst001  
       2018-10-01 20:04:17 +08:00
    这个逻辑看起来就有问题吧,参数类型是 F,然后你就直接 f('foo'),编译器怎么知道你到时候传进来的 f 是 (a: string) => void 还是 (b: boolean) => void ?
    kernel
        3
    kernel  
    OP
       2018-10-01 20:05:49 +08:00
    @hst001 F 是这二个函数 overload 在一起的效果,当然可以根据参数来自动判断
    把 type F =
    ((a: string) => void) |
    ((b: boolean) => void)
    改成
    type F =
    ((a: string) => void) &
    ((b: boolean) => void)

    就可以了
    kernel
        4
    kernel  
    OP
       2018-10-01 20:08:43 +08:00   1
    话说 typescript 开始起飞了,不建一个节点吗,毕竟和 js 还是完全不同的 @livid
    kernel
        5
    kernel  
    OP
       2018-10-01 20:14:27 +08:00
    @hst001 你说的是,用 | 的话是不知道传进来的具体是哪个,因为它不是重载函数了
    hst001
        6
    hst001  
       2018-10-01 20:25:59 +08:00
    @kernel #5 改成 & 表示取类型交集,换句话说,你等于告诉编译器,你传给 f2 的参数 f 是可以支持同时支持 string 和 boolean,所以就能编译通过了
    kernel
        7
    kernel  
    OP
       2018-10-01 20:49:48 +08:00
    @hst001 对,&才是函数重载,之前以为是|
    VDimos
        8
    VDimos  
       2018-10-01 22:49:18 +08:00 via Android   1
    这个和重载不重载无关,联合类型并不是或的意思,它本身就是一个独立的类型,所以不能直接调用,它没有 call signature。如果你使用交叉类型,两个函数签名交叉类型依旧是函数,所以有 call signature,才能编译。交叉类型不应该用在函数上,这个产生的结果很抽象,应该用在对象上面。你这个类型应该把参数改为 string 和 boolean 的联合类型,而不是独立成两个函数再联合
    NickCarter
        9
    NickCarter  
       2018-10-01 23:27:33 +08:00
    type F = (a: string | boolean) => void
    azh7138m
        10
    azh7138m  
       2018-10-01 23:58:28 +08:00
    楼上的写法是更好的选择
    关于重载,官方文档也有写示例,https://www.typescriptlang.org/docs/handbook/functions.html,可以写完声明,再去写具体的定义
    kernel
        11
    kernel  
    OP
       2018-10-02 00:18:25 +08:00   1
    @VDimos &用在多个函数上就是表示的是重载的意思吧。把参数改成 string | boolean 不是个办法,因为可能不同函数参数个数不一样
    VDimos
        12
    VDimos  
       2018-10-02 11:10:02 +08:00
    @kernel &用在函数上很抽象,我在官方文档里也没看见关于这个的讲解。你甚至可以在后面&一个任何类型,在编译时都会当作它有 call signature,但是实际上并没有
    kernel
        13
    kernel  
    OP
       2018-10-02 11:51:58 +08:00
    @VDimos 我是在搜 issue 列表发现&用在函数上就表示重载(而且不用&还真没有别的办法)。至于为什么一个函数可以&一个非函数而不报错,这可能是 ts 的缺陷吧。
    franklinyu
        14
    franklinyu  
       2018-10-03 10:50:36 +08:00
    「搜 issue 列表发现&用在函数上就表示重载」真的?哪个 issue ?很有兴趣知道
    kernel
        15
    kernel  
    OP
       2018-10-03 11:38:58 +08:00
    vsomeone
        16
    vsomeone  
       2018-10-03 13:47:06 +08:00
    不太懂这个重载是怎么写的… TypeScript 里的重载应该是下面这样吧

    ```typescript
    class Person {}
    class Pet {}
    class Shop {}

    type Shopping = {
    (a: Person): void;
    (b: Pet, c: Shop): void;
    };

    let shop: Shopping = (a?: Person, b?: Pet, c?: Shop) => {
    if (a instanceof Person) {}
    else if (b instanceof Pet && c instanceof Shop) {}
    }

    ```
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5148 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 22ms UTC 09:32 PVG 17:32 LAX 02:32 JFK 05:32
    Do have faith in what you're doing.
    ubao 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