尝试执行keyof,但将有效属性限制为字符串类型

时间:2019-02-16 20:16:18

标签: typescript typescript-typings

我遇到了Typescript的一个小问题。我正在尝试编写一些函数来简化对Redux状态的处理。

我具有用于创建某些实体状态的此接口:

export interface NormalizedState<T> {
  byId: { [id: string]: T };
  allIds: string[];
}

我有一些这样的MailState:

export interface MailState extends NormalizedState<Mail> {
  inbox: string[]
}

我有一个函数可以像这样添加到byId属性:

type StringPropertyNames<T> = { [K in keyof T]: T[K] extends string ? K : never }[keyof T];

const appendToState = <T, K extends StringPropertyNames<T>>(s: NormalizedState<T>) => (v: T[], p: K) => 
  v.reduce((acc, m) => ({ ...acc, [m[p]]: m }), s.byId);

问题是我在appendToState函数中遇到错误

[m[p]]

我收到以下错误:

  

计算出的属性名称必须为“字符串”类型,   “数字”,“符号”或“任何”。

所以我输入的内容似乎已关闭。任何帮助将不胜感激!

1 个答案:

答案 0 :(得分:1)

您的类型很好,对于呼叫者来说应该可以。问题在于,在函数Typescript中,条件类型实际上不能做很多事情。因此,它不会试图找出T[K]会变成string的情况,它只会看到条件并放弃。

简单的解决方案是使用类型断言。

const appendToState = <T, K extends StringPropertyNames<T>>(s: NormalizedState<T>) => (v: T[], p: K) => 
  v.reduce((acc, m) => ({ ...acc, [m[p] as string]: m }), s.byId);

另一种解决方案是颠倒您表达条件的方式。可以说K必须具有类型T的属性string而不是T是类型K的{​​{1}}的任何键。对于编译器来说,这种替代方法更容易

string