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

如何让 TypeScript 正确推导计算属性名的引用?

  •  
  •   SilentDepth · 2018-11-03 15:58:17 +08:00 · 5671 次点击
    这是一个创建于 2204 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如有这么一个类:

    class Something {
      set (key: string, val: any) {
        this['set$' + key](val)
        // 上面这句会有类型错误提示
      }
    
      set$name (name: string) {...}
    
      set$age (age: number) {...}
    }
    

    在启用 noImplicitAny 时 TS 会报错:'Something' has no index signature.(在 this[...] 部分)。然而并不知道如何标注类型。

    key 可能的取值有一个明确的列表,其类型在这里也可以写成 key: 'name' | 'age'。所以虽然这种计算属性名是运行时逻辑,但理论上是可以在编译时分析的(字面量和固定值的计算)。于是问题就是 TS 现在是否支持这种分析?

    PS: 刚注意到 V2EX 还没有 TS 节点。

    第 1 条附言  ·  2018-11-03 21:37:50 +08:00
    我是想用 TS 实现这段代码的效果:

    https://jsfiddle.net/SilentDepth/3ydpra7q/
    15 条回复    2018-11-04 23:58:55 +08:00
    kernel
        1
    kernel  
       2018-11-03 16:04:40 +08:00
    不可能的,你把 set$name 方法前的 set$去掉还有一点可能
    des
        2
    des  
       2018-11-03 16:44:35 +08:00 via Android
    不可能
    SilentDepth
        4
    SilentDepth  
    OP
       2018-11-03 17:24:12 +08:00
    @vghdjgh #3 Options 里开启 noImplicitAny 后,错误提示出现。
    SilentDepth
        6
    SilentDepth  
    OP
       2018-11-03 21:00:17 +08:00
    @kcats #5 这是不是和 @ts-ignore 一个效果……

    再尝试搜索了一下,放弃从 TS 寻找原生解决方案了。个人觉得这也算 JS 编码的常见套路,希望 TS 早日能支持这个特性吧。
    buhi
        7
    buhi  
       2018-11-03 21:11:01 +08:00
    这个虽然是 js 编码的常见套路, 但是不能称得上一个好套路, 所以不支持也无可厚非.
    如果改成这样那就可以支持
    ```
    type Properties = {
    name:string,
    age:number
    }
    class Foo {
    set<k extends keyof Properties>(key:k, value: Properties[k]){
    this.properties[key] = value
    }
    properties:Properties
    }
    const f = new Foo()
    f.set("name",233) //报错
    ```
    SilentDepth
        8
    SilentDepth  
    OP
       2018-11-03 21:22:09 +08:00
    @buhi #7 我是想实现 3 点效果:单一 API ( set 方法)、set 过程有副作用(不是赋值这么简单)、派生类可以覆盖其中某个 set 方法。暂时没想到 TS 里有什么好的套路。
    SilentDepth
        9
    SilentDepth  
    OP
       2018-11-03 21:37:10 +08:00
    我是想用 TS 实现这段代码的效果:

    https://jsfiddle.net/SilentDepth/3ydpra7q/
    kcats
        10
    kcats  
       2018-11-03 21:52:20 +08:00
    @SilentDepth 这是标准的写法呀, 类型的 key 可以是不定的, 类也是一样, 比如

    type Map<T> = { [P: string]: T }

    和 @ts-ignore 完全不是一个东西, 代码里面理论上一定不要用 @ts-ignore 这个东西
    SilentDepth
        11
    SilentDepth  
    OP
       2018-11-03 21:57:56 +08:00
    @kcats #10 我明白,我是说,这个 index signature 只是告诉编译器兼容未知的引用,并没有帮助类型推断,从结果上和 ts-ignore 没啥区别。
    kcats
        12
    kcats  
       2018-11-03 23:35:41 +08:00
    @SilentDepth 这个性质是完全不一样的, ts-ignore 是跳过 ts 的静态类型检测, 意味着无论是对的还是错的都会被跳过, 这样带来的效果就是写这样的 ts 还不如直接写 js, 而上面说的形式是你明确知道这个类型的数据结构的.

    其实还有一种方法, 就是直接用 any 跳过:

    set(key, value) {
    (this as any)['key' + key](value)
    }
    FrankFang128
        13
    FrankFang128  
       2018-11-04 01:00:49 +08:00
    那还不如用 JS 写
    SilentDepth
        14
    SilentDepth  
    OP
       2018-11-04 22:54:22 +08:00
    @FrankFang128 #13 这意思是,这样的需求不适合用 TS 实现吗?(需求要点见 #8 )
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2835 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 07:40 · PVG 15:40 · LAX 23:40 · JFK 02:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.