【发布时间】:2019-06-12 08:58:03
【问题描述】:
升级到 TypeScript 3.5 导致我的一些代码不再编译。我认为这是因为一个重大变化:Generic type parameters are implicitly constrained to unknown。我正在尝试找到修复代码的最佳方法。
TL;DR:如何声明类型为 T 和 K extends keyof T 的泛型函数,但其中 T[K] 必须是字符串。
加长版:我想将一个对象数组转换为一个对象,该对象具有数组中的所有值,并以对象的某些属性为键。例如:
type Person = { id: string, firstName: string, lastName: string, age: number}
const array: Person[] = [
{id: "a", firstName: "John", lastName: "Smith", age: 27},
{id: "b", firstName: "Bill", lastName: "Brown", age: 53}
]
const obj = convertArrayToObject(array, "id")
这样做的结果是obj 将具有以下结构:
{
a: {id: "a", firstName: "John", lastName: "Smith", age: 27},
b: {id: "b", firstName: "Bill", lastName: "Brown", age: 53}
}
我有这个功能来做到这一点:
type ItemsMap<T> = { [key: string]: T }
function convertArrayToObject<T>(array: Array<T>, indexKey: keyof T): ItemsMap<T> {
return array.reduce((accumulator: ItemsMap<T>, current: T) => {
const keyObj = current[indexKey]
const key = (typeof keyObj === "string") ? keyObj : keyObj.toString()
accumulator[key] = current
return accumulator
}, {})
}
自从升级到 TypeScript 3.5 后,错误出现在调用 toString:Property toString does not exist on type T[keyof T]。
我可以理解这个问题:由于 TypeScript 3.5 中的重大更改,current[indexKey] 的返回值现在是unknown 而不是一个对象,所以toString 不能被调用。但是我该如何解决呢?
理想情况下,我想做的是对indexKey 参数的类型设置一个通用约束,这样您只能传入一个返回值本身就是字符串的键。以下是我到目前为止所取得的成果(虽然我不确定这是否是最好的方法):
首先,我声明一个类型,用于查找给定类型TObj 的所有属性,它返回给定类型的结果TResult:
type PropertiesOfType<TObj, TResult> =
{ [K in keyof TObj]: TObj[K] extends TResult ? K : never }[keyof TObj]
例如,我现在可以获得Person 的所有字符串属性:
type PersonStringProps = PropertiesOfType<Person, string> // "firstName" | "lastName" | "id"
现在我可以将函数声明如下:
function convertArrayToObject<T, K extends PropertiesOfType<T, string>>(
array: Array<T>, indexKey: K): ItemsMap<T> { ...
我现在只能调用带有返回字符串的属性的函数,例如:
convertArrayToObject(array, "id") // Compiles, which is correct
convertArrayToObject(array, "age") // Doesn't compile, which is correct
但是,在函数体中,我似乎仍然无法使用传入的keyof T 并让编译器知道返回的值是一个字符串:
return array.reduce((accumulator: ItemsMap<T>, current: T) => {
const key: string = current[indexKey]
这不能编译:Type T[K] is not assignable to type string。我可以通过投射来解决这个问题:
const key: string = current[indexKey] as unknown as string
我想这是安全的,因为我知道current[IndexKey] 是一个字符串。但这似乎仍然不太正确。
【问题讨论】:
标签: typescript