如果在TypeScript中使用字符串访问对象属性,如何获得正确的类型



假设我有以下代码:

interface Response { 'property.a': number; 'property.b': string }
const response: Response = {
'property.a': 10,
'property.b': 'foo'
}

我想以一种类型安全的方式访问response的属性,但它并不像我所期望的那样完全起作用。我正在寻找一种用字符串访问对象属性的方法,其中

  1. 如果对象具有属性,则访问该属性会给出正确的类型
  2. 如果对象没有属性,则访问它会引发错误

如果您直接访问属性,则会发生以下情况:

response['property.a'] // works as expected: is of type number
response['property.c'] // should throw an error, but doesn't

所以条件1是满足的,但条件2不是。我还尝试了以下内容:

const get = <T>(obj: T, key: keyof T) => obj[key]
get(response, 'property.a') // should be of type number, but is number | string;
get(response, 'property.c') // works as expected: throws error

因此,至少抛出了错误,但现在它返回Response中所有可能的属性类型的并集——该方法在条件1下失败,但满足条件2。

有没有一种方法同时满足这两个条件?

编辑:

我刚刚发现有一个名为noImplicitAny的TypeScript规则可以实现这种行为!不幸的是,我无法在当前工作的代码库中启用此规则,因此我将保留此问题,以防有其他解决方法。

对于直接属性访问,除非您没有启用--noImplicitAny编译器选项,否则您肯定会得到一个错误,这是"标准";--strict编译器选项套件。几乎普遍建议启用--strict


关于你的get()函数方法:

由于key是类型keyof T,那么obj[key]将是索引访问类型T[keyof T],它将是T中所有已知属性类型的并集。

如果您想跟踪作为key参数传入的特定密钥的文字类型,那么get()函数需要在该类型中是通用的,如下所示:

const get = <T, K extends keyof T>(obj: T, key: K) => obj[key]

现在key是被约束到keyof T的一般类型K,并且obj[key]被推断为索引访问类型T[K]。让我们测试一下:

const num = get(response, 'property.a');
// const num: number

这里,根据需要,T被推断为ResponseK被推断为"property.a",因此T[K]number

游乐场链接到代码

最新更新