使用字符串访问属性

时间:2019-08-31 08:56:05

标签: typescript

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

我有以下界面

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

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

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

TS抱怨“ nestedProperty”没有字符串索引类型。如果我加上typeguard(例如if (attributeName === "a"))编译器是否满意,但我真的不想走if (...===... || ...===... || ... ) {路线。

我也不想使用索引类型:

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

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

我敢肯定有一些优雅的方法可以做到,但是似乎在文档/ Stack Overflow / web的任何地方都找不到。

我应该为此编写自定义后卫返回联合类型谓词吗? 像这样吗?

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

2 个答案:

答案 0 :(得分: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)

答案 1 :(得分:0)

我会选择:

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)

鉴于此问题,如果您不想声明其他类型,则可以采用这种方法。但是我喜欢更明确声明的内容,例如接受的答案。