我感觉自己像个骗子,因为我用过@aleksxor no-type-safe-way
关联。抱歉,我只是认为值得一些解释。
我相信这个论点 https://github.com/microsoft/TypeScript/issues/34591#issuecomment-544180947相当不错:
这不是一个错误。
T = { hello : "bye" }
现在,你的任务是,
map["hello"] = "hi there"
不健全
考虑以下示例:
let index: { [key: string]: any } = {}
let immutable = {
a: 'a'
} as const
let record: Record<'a', 1> = { a: 1 }
index = immutable // ok
index = record // ok
const foo = (obj: { [key: string]: any }) => {
obj['sdf'] = 2
return obj
}
const result1 = foo(immutable) // safe, see return type
const result2 = foo(record) // safe , see return type
它有效,因为 TS 不会尝试推断obj
来自一般论证。我们可以使用任何我们想要的字符串作为索引。
让我们回到我们的问题,现在,TS 尝试推断对象的类型
const foo = <T extends { [key: string]: any }>(obj: T) => {
obj['sdf'] = 2 // error
}
{[key:string]:any}
太宽了。
不健全的例子:
let index: { [key: string]: any } = {}
let immutable = {
a: 'a'
} as const
let record: Record<'a', 1> = { a: 1 }
index = immutable // ok
index = record // ok
const foo = <T extends { [key: string]: any }>(obj: T) => {
obj['sdf'] = 2
return obj
}
const result1 = foo(immutable) // unsound, see return type
const result2 = foo(record) // unsound , see return type
因此,虽然您可以通过键获取值,但禁止通过键进行突变是安全的。
顺便说一句,TS 不能很好地处理突变,因为它无法跟踪它们。Here https://stackoverflow.com/questions/67660342/why-does-typescript-say-this-variable-is-referenced-directly-or-indirectly-in-i你还有另一个很好的例子为什么最好避免突变
如果 TypeScript 不知道 T 中存在该键,则无论读取还是写入, result[key] 都应该是错误。我明白为什么写作可能不健全而阅读则不然,我认为第一句话只是一个切线。
如果您阅读财产 - 它不会影响T
对象,你可以返回T
没有任何问题。
const foo = <T extends { [key: string]: any }>(obj: T) => {
const readOperation = obj['sdf']
// object still has T type
return obj
}
但如果你改变它:
const foo = <T extends { [key: string]: any }>(obj: T) => {
obj['sdf'] = 2
// this is not our good old `T` anymore,
return obj
}
TS 无法确定函数的返回类型。
类型签名是
const foo: <T extends {
[key: string]: any;
}>(obj: T) => T
但事实并非如此T
不再如此,因为它发生了突变,而且 TS 不跟踪突变 - 这样做是不安全的。