【发布时间】:2023-01-12 05:12:28
【问题描述】:
我有一个名为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 不知道我们正确地为 [key] 分配了值,因为在 liftedFunction 的返回类型中显式输入。
你怎么能避免 TypeScript 在这里因为一切正常而对你大喊大叫呢?
我尝试省略 liftedFunction 的返回类型的显式类型。但是,TypeScript 不知道函数结果分配给的键的正确返回类型。
【问题讨论】:
-
您的问题可以简化为以下内容:tsplay.dev/N5OJ2W - 具有与之关联的通用类型的键的使用得到扩大。
标签: typescript object key typescript-typings typescript-generics