我是TypeScript的新手,并且碰到了一些东西。
我有一个普通的函数对象,这些函数在某种状态下运行,如下所示:
const queries = {
getRoom(state: State, roomID: string) {
return state.rooms[roomID]
},
isPlayerInRoom(state: State, roomID: string) {
return state.player.roomID === roomID
}
}
我想转换此对象,以便可以在没有第一个参数的情况下调用每个函数。
在常规JS中,我可能只是做类似的事情:
function wrap(object, store) {
const newObject = {}
for (const name in object) {
const func = object[name]
newObject[name] = (...args) => func(store.getState(), ...args)
}
return newObject
}
const newQueries = wrap(queries, store)
newQueries.getRoom(5)
但是使用TypeScript时,类型不会保留。
如何确保我的wrap函数具有正确的返回类型?
我确定我可以在这里采用其他方法,但是我宁愿学习如何精确地执行此操作,因为将来可能会派上用场。
谢谢!
答案 0 :(得分:2)
我认为编译器不够聪明,无法遵循该函数的流程并推断出您想要它们的类型。根据TypeScript标准库,Object.entries(obj)
个元组中的[string, T]
returns an array个,其中T
是obj
所有属性类型的并集。为了甚至开始希望编译器自动为您完成此操作,您需要Object.entries(obj)
返回可以编写的类型为[K0, V0] | [K1, V1] | ...
的相关键值类型的数组,但这是仅仅为一个用例尝试augment键入Object.entries()
可能不值得。
相反,您可以做的是自己代表所需的类型操作,这将是mapped和conditional类型的组合。然后,创建一个generic函数,该函数的调用签名返回此类型,并且其实现使用所需的type assertions数量,以使编译器对无法验证的类型感到满意...或等效地,用所需的签名执行单个overload,而实现签名则不够宽松,以使编译器不会抱怨。像这样:
// pull the first argument off a function
type StripFirstArgument<F extends (...args: any[]) => any> =
F extends (first: any, ...rest: infer A) => infer R ? (...args: A) => R : never;
// take an argument of type A, and an object of type T
// where T's properties are all functions whose first argument is type A
// and return a new object of partially applied functions
function partiallyApplyObject<A, T extends {
[K in keyof T]: (a: A, ...rest: any[]) => any
}>(
a: A,
t: T
): { [K in keyof T]: StripFirstArgument<T[K]> };
// lax implementation signature
function partiallyApplyObject(a: any, t: { [k: string]: Function }) {
const ret: { [k: string]: Function } = {};
for (let [k, f] of Object.entries(t)) {
ret[k] = (...args: any[]) => t[k](a, ...args);
}
return ret;
}
让我们看看它是否有效:
const newQueries = partiallyApplyObject(store.getState(), queries);
newQueries.getRoom(5); // error, 5 isn't a string
newQueries.isPlayerInRoom("five"); // boolean
对我很好。也许这可能是您想要的更复杂,但是希望它是有道理的,无论如何您都可以体会到希望编译器自动执行的任务范围。
好的,希望能有所帮助。祝你好运!