比如有这么一个类:
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
kernel 2018-11-03 16:04:40 +08:00
不可能的,你把 set$name 方法前的 set$去掉还有一点可能
|
2
des 2018-11-03 16:44:35 +08:00 via Android
不可能
|
3
vghdjgh 2018-11-03 16:52:35 +08:00
|
4
SilentDepth OP @vghdjgh #3 Options 里开启 noImplicitAny 后,错误提示出现。
|
5
kcats 2018-11-03 18:05:53 +08:00
```typescript
class Foo { [P: string]: any set(name: string, value: any) { this['key' + name](value) } foo() { console.log('foo') } } const a = new Foo() a.foo() // error // a.foo(1) ``` [Playground]( https://www.typescriptlang.org/play/#src=class%20Foo%20%7B%0D%0A%20%20%5BP%3A%20string%5D%3A%20any%0D%0A%20%20set(name%3A%20string%2C%20value%3A%20any)%20%7B%0D%0A%20%20%20%20this%5B'key'%20%2B%20name%5D(value)%0D%0A%20%20%7D%0D%0A%0D%0A%20%20foo()%20%7B%0D%0A%20%20%20%20console.log('foo')%0D%0A%20%20%7D%0D%0A%7D%0D%0A%0D%0Aconst%20a%20%3D%20new%20Foo()%0D%0Aa.foo()%0D%0A%2F%2F%20error%0D%0A%2F%2F%20a.foo(1)) |
6
SilentDepth OP |
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) //报错 ``` |
8
SilentDepth OP @buhi #7 我是想实现 3 点效果:单一 API ( set 方法)、set 过程有副作用(不是赋值这么简单)、派生类可以覆盖其中某个 set 方法。暂时没想到 TS 里有什么好的套路。
|
9
SilentDepth OP |
10
kcats 2018-11-03 21:52:20 +08:00
@SilentDepth 这是标准的写法呀, 类型的 key 可以是不定的, 类也是一样, 比如
type Map<T> = { [P: string]: T } 和 @ts-ignore 完全不是一个东西, 代码里面理论上一定不要用 @ts-ignore 这个东西 |
11
SilentDepth OP @kcats #10 我明白,我是说,这个 index signature 只是告诉编译器兼容未知的引用,并没有帮助类型推断,从结果上和 ts-ignore 没啥区别。
|
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) } |
13
FrankFang128 2018-11-04 01:00:49 +08:00
那还不如用 JS 写
|
14
SilentDepth OP @FrankFang128 #13 这意思是,这样的需求不适合用 TS 实现吗?(需求要点见 #8 )
|