使用字符串变量作为属性名称的动态类型

时间:2018-07-13 17:57:45

标签: typescript

我希望能够使用属性名称(指定参数之一)动态地构造类型。虽然可以构造实际的对象,但似乎无法构造实际的类型。我想将这种类型用于合成更改

[org.springframework.context.annotation.AnnotationConfigApplicationContext@150c158: startup date [Fri Jul 13 18:40:48 BST 2018]; root of context hierarchy]

发出的错误如下:

  

类型文字中的计算属性名称必须引用表达式   其类型为文字类型或“唯一符号”类型。

示例游乐场:http://www.typescriptlang.org/play/#src=%0D%0Aexport%20function%20mapProp%3CAssignedType%3E(value%3A%20AssignedType%2C%20propertyName%3A%20string)%20%7B%0D%0A%0D%0A%20%20type%20ReturnType%20%3D%20%7B%0D%0A%20%20%20%20%5BpropertyName%5D%3A%20value%0D%0A%20%20%7D%3B%0D%0A%0D%0A%20%20return%20%7B%0D%0A%20%20%20%20%5BpropertyName%5D%3A%20value%0D%0A%20%20%7D%3B%0D%0A%7D

1 个答案:

答案 0 :(得分:4)

我认为您将获得的最接近的东西是这样的:

export function mapProp<PropertyName extends string, AssignedType>(
  value: AssignedType, 
  propertyName: PropertyName
) {

  type ReturnType = {
    [K in PropertyName]: AssignedType
  }; 
  // equivalent to Record<PropertyName, AssignedType>

  return {
    [propertyName]: value
  } as ReturnType;

}

在这种情况下,您将使用mapped type而不是带有index signature的类型。如果您将字符串文字传递给PropertyName通用类型参数,则可以缩小通过string的键的范围:

const thing = mapProp(123, "abc");
thing.abc; // number
thing.def; // error

在那种情况下,ReturnType等效于{abc: number}。如果您只知道密钥在编译时是string,那么您会得到:

declare const propName: string;
const stuff = mapProp(123, propName);
stuff.abc; // number
stuff.def; // number 

现在ReturnType等效于{[k: string]: number},表示它接受任何string键(并给它一个number值)。这可能不是您想要的,但是在这种情况下,这是编译器可以做的最好的事情。

还要注意,在不使用类型断言(as ReturnType)的情况下,计算后的属性通常以字符串索引而不是更具体的形式结束。当前,它是TypeScript的design limitation。已经有一些attempts可以解决这个问题,但是还没有任何语言能够使它成为语言。

希望有所帮助;祝你好运!