You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript:为对象所有属性应用泛型函数并推导返回值

TypeScript批量转换选择器对象的类型标注方案

我在TypeScript中实现了单个选择器的转换函数createModifiedSelector,但当选择器数量较多时,希望批量转换整个选择器对象,目前的createModifiedSelectorsObj存在类型标注问题:需要替换Record<keyof R, any>中的any,同时解决循环中createModifiedSelector调用的TS2345类型错误。

原代码如下:

type State = {
    alpha: string,
    beta: number
}

const selectors = {
    alpha: (s: State) => s.alpha,
    beta: (s: State) => s.beta
}

function createModifiedSelector<T, S, U>(
  modifyState: (differentState: T) => S,
  selector: (state: S) => U,
) {
  return (differentState: T) => selector(modifyState(differentState));
}

const add2State = (state: any) => {
    return {...state, alpha: "abc", beta: 123}
}

// 单个选择器转换可正常运行
const modifiedAlpha = createModifiedSelector(add2State, selectors.alpha)
console.log(modifiedAlpha({}));

// 批量转换选择器对象的函数存在类型问题
function createModifiedSelectorsObj<T, S, R extends typeof selectors>(modifyState: (differentState: T) => S, selectors: R) {
    const result: Record<keyof R, any> = selectors;     // 这里应该用什么类型替代any?
    let selectorKey: keyof R;
    for (selectorKey in selectors) {
        result[selectorKey] = createModifiedSelector(modifyState, selectors[selectorKey])       // 如何解决TS2345错误?
    }
    return result;
}

修正后的完整实现

通过映射类型定义返回值结构,并通过类型断言解决循环中的类型不兼容问题,以下是正确的代码:

type State = {
    alpha: string,
    beta: number
}

const selectors = {
    alpha: (s: State) => s.alpha,
    beta: (s: State) => s.beta
}

function createModifiedSelector<T, S, U>(
  modifyState: (differentState: T) => S,
  selector: (state: S) => U,
) {
  return (differentState: T) => selector(modifyState(differentState));
}

const add2State = <T>(state: T) => {
    return {...state, alpha: "abc", beta: 123} as const;
}

// 映射类型:将原选择器转换为接收T类型参数的新函数
type ModifiedSelectors<T, R> = {
    [K in keyof R]: R[K] extends (state: infer S) => infer U 
        ? (differentState: T) => U 
        : never;
};

function createModifiedSelectorsObj<T, S, R extends Record<string, (state: S) => any>>(
    modifyState: (differentState: T) => S,
    selectors: R
): ModifiedSelectors<T, R> {
    const result = {} as ModifiedSelectors<T, R>;
    for (const selectorKey in selectors) {
        if (selectors.hasOwnProperty(selectorKey)) {
            result[selectorKey] = createModifiedSelector(modifyState, selectors[selectorKey]) as ModifiedSelectors<T, R>[typeof selectorKey];
        }
    }
    return result;
}

// 使用示例
const modifiedSelectors = createModifiedSelectorsObj(add2State, selectors);
// 类型正确:modifiedSelectors.alpha() 返回 string,modifiedSelectors.beta() 返回 number
console.log(modifiedSelectors.alpha({})); // "abc"
console.log(modifiedSelectors.beta({})); // 123

核心要点

  • 映射类型ModifiedSelectors:遍历原选择器对象的每个键,通过条件类型推断原选择器的输入和输出类型,将其转换为接收T类型参数的新函数
  • 泛型约束:将R约束为Record<string, (state: S) => any>,确保每个属性都是符合要求的选择器函数
  • 类型断言:初始化result时断言为目标类型,赋值时再次断言对应键的类型,绕过TypeScript对循环赋值的类型检查限制

内容的提问来源于stack exchange,提问作者Sentenza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 23:00:54