我有一个枚举:
enum MyEnum {
One,
Two,
Three
}
然后我有一个React Component方法,该方法应该返回一个对象,该对象的键只能是MyEnum的字符串键(到目前为止,含义是:1、2、3):
myFunction = (someValue: {}[]): {} => {
return someValue.reduce((res, v, i) => {
res[v.name].push(v)
return res
}, {})
}
问题:如何动态地将此函数的返回值类型定义为对象,其键只能是MyEnum的字符串键?
现在只有3个,但是如果我向枚举添加另一个,则myFunction返回值的类型也应该更新。
更新1:
尝试分配Record<keyof typeof MyEnum, any>
作为返回值:
myMethod = (someValue: {}[]): Record<keyof typeof MyEnum, any> => {
return someValue.reduce((res: any, v: SomeInterface) => {
res[v.name].push(v)
return res
}, {})
}
这不会引发任何错误,但是如果我将reduce的返回值分配给变量,然后在其上添加另一个属性(其键不是MyEnum键),就不会有错误,这不是我要查找的:
myMethod = (someValue: {}[]): Record<keyof typeof MyEnum, any> => {
let someVar = someValue.reduce((res: any, v: SomeInterface) => {
res[v.name].push(v)
return res
}, {})
someVar.keyName = 'value'
return someVar
}
答案 0 :(得分:1)
因此,似乎这里发生了很多事情。我的观察和猜测:
由于v
是SomeInterface
,因此看来someValue
必须是SomeInterface
的数组。
我猜想res
的回调函数中的reduce
是myMethod
的期望返回值,因为您是在回调函数。如果我们使用名称myMethod
来调用RetType
的返回值类型,则意味着RetType
的键必须为keyof typeof MyEnum
。
您将v.name
用作这些键,并且由于v
是SomeInterface
,所以我猜想SomeInterface
的{{1}}属性应该也为name
。
您正在keyof typeof MyEnum
将push
放入v
的值上,因此您希望res
的属性是res
的数组。因此,SomeInterface
类似于RetType
,其中Record<K,V>
是标准库中的一种类型,表示一个对象,该对象具有Record<keyof typeof MyEnum, SomeInterface[]>
中的键和K
中的值。 / p>
但是,当然,由于V
可能是一个空数组,或者没有像someValue
的键那样多的元素,因此MyEnum
可能缺少某些属性。因此,它更像RetType
,其中Partial<T>
是标准库中的一种类型,它使Partial<Record<keyof typeof MyEnum, SomeInterface[]>>
中的属性是可选的。
现在,我不确定您是否完全了解reduce
的工作方式,但是回调需要返回与预期返回值相同类型的东西。第二个参数是“初始值”,它还必须与预期的返回值具有相同的类型。因此,我必须更改您的回调,以使其返回T
,并更改初始值,使其也为res
。
我还注意到,由于初始值是一个空对象,因此当您首次尝试将某物RetType
放入其数组属性之一时,您会发现它是push
。因此,您需要检查并将其设置为空数组,然后再尝试undefined
。
这使我想到了这样的东西:
push
请注意,我在一个名为enum MyEnum {
One,
Two,
Three
}
interface SomeInterface {
name: keyof typeof MyEnum
};
type RetType = Partial<Record<keyof typeof MyEnum, SomeInterface[]>>
const myMethod = (someValue: SomeInterface[]): RetType => {
let someVar = someValue.reduce((res: RetType, v: SomeInterface) => {
const resVName = res[v.name] || []; // make sure it's set
resVName.push(v);
res[v.name]=resVName; // copy back in case it's a new array
return res;
}, {} as RetType)
//someVar.keyName = 'value' // errors now
return someVar
}
的新值中进行复制。这使编译器的control flow analysis可以正常工作,并确保resVName
实际上是resVName
而不是SomeInterface[]
。由于TypeScript中有bug/limitation,因此它无法在SomeInterface[] | undefined
上运行,因此控制流分析不适用于括号属性访问符号。有点烦人,但确保类型安全可能值得。
该代码的类型都很好,并且可能在运行时有效(您需要检查)。但是res[v.name]
似乎与您要执行的操作不同。相反,我想说的是您正在寻找更简单的forEach
方法,例如:
reduce
这也可行,不会在累加器周围传递。两种方法都可以,
好的,希望这能给您带来一些想法并给您一些想法。祝你好运!