我有2个对象,它们是相同的道具,但是不同的道具结果。
const tom = {
getAction: () => ({
eat: () => {},
sleep: () => {},
}),
}
const steve = {
getAction: () => ({
work: () => {}
}),
}
我的func希望将2个对象和额外的getAction函数结合到父级
const mapObjIndexed = <K extends string, T, R>(fn: (value: T) => R, data: Record<K,T>) => {
return Object.keys(data).reduce((previous, key) => ({
...previous,
[key]: fn(data[key])
}),{})
}
interface Person<T> {
getAction: () => T
}
const combineAction = <G, K extends string, T extends Person<G>>(people: Record<K, T>) => {
return mapObjIndexed((item) => item.getAction(), people)
}
const actions = combineAction({tom, steve})
// So I can do like this
actions.tom.eat() // problems at tom
actions.tom.sleep() // same
actions.steve.work() // same
这里有2个问题:
第一:如何定义mapObjectIndexed的返回类型
2nd:打字稿如何知道汤姆道具包含饮食功能和史蒂夫工作原理
谢谢帮助
答案 0 :(得分:0)
根据您指定的参数类型,mapObjIndexed
的自然返回类型为Record<K, R>
。 (您必须将返回的表达式强制转换为Record<K, R>
,因为TypeScript不够聪明,无法看到您正在逐个添加所有必需的属性。)
但是,这对于combineAction
用例没有用,因为combineAction
输入中的每个人都有一个不同类型T
,而您想要输出的相应属性具有相应的类型R
。您可以使用映射类型如下表示combineAction
的类型:
const combineAction = <P extends { [N in keyof P]: Person<{}> }>(people: P):
{ [N in keyof P]: ReturnType<P[N]["getAction"]> } => {
return <any>mapObjIndexed((item) => item.getAction(), people)
}
但是,没有一种好的方法来声明mapObjIndexed
的类型,该类型将允许您通过对combineAction
的调用而无需强制转换来实现mapObjIndexed
,因为您实际上必须参数化在原始属性类型mapObjIndexed
与转换后的属性类型P[N]
之间的关系上ReturnType<P[N]["getAction"]>
。为此,mapObjIndexed
必须具有一个higher-kinded type,尽管存在一些有限的解决方法,但TypeScript目前不支持该an example。如果您遇到这种情况,我可能会声明combineAction
的类型,而不用担心实现中的类型转换。