【问题标题】:Accessing property using string使用字符串访问属性
【发布时间】:2019-08-31 17:57:25
【问题描述】:

使用字符串访问接口/类属性的正确方法是什么?

我有以下界面

interface Type {
  nestedProperty: {
    a: number
    b: number
  }
}

我想像这样使用数组迭代来设置嵌套属性:

let myType:Type = ...
["a", "b"].forEach(attributeName => myType.nestedProperty[attributeName] = 123)

TS 抱怨“nestedProperty”没有字符串索引类型。如果我添加 if typeguard(例如if (attributeName === "a")) 编译器很高兴,但我真的不想去if (...===... || ...===... || ... ) { 路由。

我也不想使用索引类型:

interface Type<T> {
  [index:string]: <T>
  a: <T>
  b: <T>
}

由于它不是动态结构,因此属性可能有不同的类型。

我确信有一些优雅的方法可以做到这一点,但似乎无法在文档/堆栈溢出/web 中的任何地方找到它。

我应该为此编写自定义保护返回联合类型谓词吗? 类似的东西?

(attribute: string): attribute is ('a' | 'b') { ... }

【问题讨论】:

  • 我不确定您的Type 接口是否只是一个通用示例。如果不是,您可以使用interface Type {nestedProperty: {[key: string]: number};}
  • 是的。那是“解决方案”之一,但我不希望 Type 成为动态结构,我可以在那里放置任何东西。我想坚持一组定义的属性。我已将问题编辑得更准确
  • 那么interface Type {nestedProperty: {[key in ('a' | 'b')]: number};}呢?

标签: typescript


【解决方案1】:

您必须明确告诉 TypeScript,您使用的数组仅包含 nestedProperty 属性中允许作为键的属性。

interface Type {
  nestedProperty: {
    a: number
    b: number
  }
}

// Create a type alias for convenience. The type itself
// is a list of keys allowed in the `nestedProperty`.
type NestedAccessors = Array<keyof Type['nestedProperty']>

// Now TS is happy to do anything with the list since it
// can guarantee you're using proper values.
(["a", "b"] as NestedAccessors).forEach(attributeName => myType.nestedProperty[attributeName] = 123)

【讨论】:

  • keyof!还没有在文档中看到那个:) 看起来很干净。非常感谢。到目前为止,TypeScripting 已经有几天了。彻底恋爱了。现在更多:)
  • 作为后续:有没有办法将 NestedAccessor 转换为数组,这样我就可以使用NestedAccessorsSomeHowTurnedIntoArray.forEach( accessor =&gt; ... )
  • 应用编译为 JavaScript 后,您无法在运行时访问接口。您可以做的最好的事情是访问实现 Type 接口的现有对象的属性。 const arr = Object.keys(myType.nestedProperty) as NestedAccessors 将获取键值,然后您可以执行 arr.forEach(...)
【解决方案2】:

我会选择:

interface Type {
  nestedProperty: {[key in ('a' | 'b')]: number}  
}

let myType:Type = {
    nestedProperty: {
        a: 1,
        b: 2,
    }
};

(["a", "b"] as Array<'a'|'b'>).forEach(attributeName => myType.nestedProperty[attributeName] = 123)

鉴于问题,如果您不想声明其他类型,这可能是一种方法。但我喜欢更明确地声明的东西,就像在接受的答案中一样。

【讨论】:

  • 感谢您展示了一些额外的“类型乐趣”:) 在访问期间进行投射看起来还不错:myType.nestedProperty[attributeName as keyof Type['nestedProperty']] = ...
猜你喜欢
  • 2016-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-23
  • 1970-01-01
  • 1970-01-01
  • 2011-12-24
相关资源
最近更新 更多