我有一个叫做liftSync
的函数。
/**
* Lifts a function into the object context.
*
* @param functionToLift - The function to lift into the object context.
* @param assignKey - The key to assign the result of the function to. Can
* overwrite an existing key of the object.
* @param argumentKeys - The keys to use as arguments for the function.
* @returns A function that takes an object and applies the values of the object
* for the argument keys to the function and assigns the result to the assign
* key, then returns that object with the new key.
*
* @example
*
* A JavaScript version of the function can be easier to understand:
*
* ```js
* const lift = (fn, key, ...args) => (obj = {}) => ({
* ...obj,
* [key]: fn(...args.map(a => obj[a])),
* });
* ```
*
* @example
*
* ```ts
* const add = (a: number, b: number) => a + b;
*
* const liftedAdd = lift(add, 'sum', 'a', 'b');
* liftedAdd({ value: true, a: 21, b: 21 });
* // { value: true, a: 21, b: 21, sum: 42 }
* ```
*/
export function liftSync<
FunctionToLift extends (...functionArguments: any[]) => any,
AssignKey extends string,
ArgumentKey extends string,
>(
functionToLift: FunctionToLift,
assignKey: AssignKey,
...argumentKeys: readonly ArgumentKey[]
) {
return function liftedFunction<
IncomingObject extends Record<ArgumentKey, any>,
>(
object: IncomingObject,
): IncomingObject & Record<AssignKey, ReturnType<FunctionToLift>> {
// @ts-expect-error TS is dumb lol
return {
...object,
[assignKey]: functionToLift(
...argumentKeys.map(argument => object[argument]),
),
};
};
}
下面是一个演示如何使用它的测试:
import { describe, expect, test } from 'vitest';
import { liftSync } from './lift';
const add = (a: number, b: number) => a + b;
describe('liftSync()', () => {
test('given a synchronous function, a key and the names for arguments: should lift it into the object context', () => {
const liftedAdd = liftSync(add, 'sum', 'a', 'b');
const result = liftedAdd({ value: true, a: 21, b: 21 });
expect(result).toEqual({
value: true,
a: 21,
b: 21,
sum: 42,
});
});
});
如您所见,我不得不使用@ts-expect-error
,因为TypeScript不知道我们在liftedFunction
的返回类型中将[key]
的值正确地赋值为显式类型。
在这里,如何避免TypeScript因为一切正常而对您大喊大叫?
我试着忽略liftedFunction
返回类型的显式类型,但是TypeScript不知道函数结果被赋值的键的正确返回类型。
1条答案
按热度按时间iszxjhcz1#
下面是一个liftSync函数,它生成正确的类型作为结果
诀窍是
as Tobj & { [P in TOutProp]: TOut }
LiftObject类型带来的其他好处: