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

TypeScript函数式对象属性的类型推断问题排查

函数式对象定义中的TypeScript类型推断问题

我在定义函数式对象时遇到了TypeScript类型推断问题,简化后的代码如下:

type TFn<I extends object, R> = {
    input: I,
    func: (input: I) => R
}

type TObj<T extends { [key: string]: [object, any] }> = { [K in keyof T]: TFn<T[K][0], T[K][1]> }

function def<T extends { [key: string]: [object, any] }>(formObject: TObj<T>) {
    return formObject;
}

const res = def({
    fnc1: {
        input: {hel: 0},
        func: (d) => {
            d.hel // 报错:类型object不存在属性hel
            return '';
        },
    },
});

const re = res.fnc1.func({}); // re类型为any,预期应为string

问题点

  1. func的参数d被推断为宽泛的object类型,无法识别input中的具体属性hel
  2. 调用res.fnc1.func后的返回值类型为any,未能正确推断出预期的string类型

当把[object, any]替换为object并将返回值设为void时,输入部分的类型推断可正常工作,但这无法满足需要自定义返回值类型的场景。

解决方案

问题根源在于原类型约束{ [key: string]: [object, any] }过于宽泛,且通过元组间接映射的方式阻碍了TypeScript的类型关联推断。我们可以调整类型定义,让TypeScript直接追踪每个属性的输入和输出类型:

方案一:简化泛型约束

type TFn<I extends object, R> = {
    input: I,
    func: (input: I) => R
}

// 直接让T对应TFn结构,无需元组中转
function def<T extends Record<string, TFn<object, any>>>(formObject: T) {
    return formObject;
}

const res = def({
    fnc1: {
        input: { hel: 0 },
        func: (d) => {
            d.hel; // 正确推断d的类型为{ hel: number }
            return '';
        },
    },
});

const re = res.fnc1.func({ hel: 0 }); // re类型正确推断为string

方案二:精确推导输入输出类型

利用条件类型提取func的返回值类型,让TypeScript自动完成更精确的推断:

type TFn<I extends object, R> = {
    input: I,
    func: (input: I) => R
}

function def<T extends Record<string, TFn<any, any>>>(formObject: {
    [K in keyof T]: TFn<T[K]['input'], T[K]['func'] extends (input: any) => infer R ? R : never>
}) {
    return formObject as T;
}

const res = def({
    fnc1: {
        input: { hel: 0 },
        func: (d) => {
            d.hel; // 类型推断正常
            return '';
        },
    },
    fnc2: {
        input: { name: 'test' },
        func: (d) => d.name.length // 返回值类型自动推断为number
    }
});

const re1 = res.fnc1.func({ hel: 0 }); // string
const re2 = res.fnc2.func({ name: 'test' }); // number

原理说明

原代码通过TObj将元组类型映射为TFn,这种间接结构会让TypeScript无法将input的具体类型关联到func的参数上,同时any会丢失返回值的类型信息。调整后直接让泛型T对应TFn的结构,或通过条件类型提取返回值类型,能让TypeScript正确追踪每个属性的输入输出类型,完成精确推断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 02:26:01