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

TypeScript从函数接口提取返回类型时出现类型推导错误

问题原因

两个核心类型定义错误导致类型校验不符合预期:

  • EdmSchema 条件判断作用域错误
    原写法对整个传入的根类型T做对象校验,而非对每个属性的类型T[K]做校验:
    // 错误实现:判断根类型T是否为对象,而非判断每个属性值T[K]
    type EdmSchema<T> = {[K in keyof T]: T extends object ? EdmSchemaValue<T[K]> : never};
    
    当传入的T是数组类型(比如IHostEntry[])时,TS会将数组识别为对象,映射出的类型是包含数组原型方法(push/pop/length等)的普通对象结构,而非预期的「元素Schema组成的数组」结构,直接导致后续returnType的数组匹配逻辑失效。
  • 数组场景类型匹配缺失
    当函数返回值是数组类型U[]时,原定义EdmMap<RT> | EdmSchema<RT>没有明确声明「数组元素可以是EdmSchema<U>类型」,TS会默认将数组元素匹配为基础类型对应的EdmSchemaValue结构,要求元素必须自带顶层type字段,因此会把hostDataSchema(本身是EdmSchema<IHostEntry>结构,无顶层type字段)判定为类型不匹配,抛出缺少type属性的错误。

修正方案

调整类型定义逻辑,明确区分数组、对象、基础类型的映射规则,补全缺失的工具类型定义:

  1. 重构EdmMap映射逻辑,自动识别数组、基础类型、对象类型,分别映射到对应Edm类型结构
  2. 修正EdmSchema定义,对每个属性值做映射,支持嵌套对象递归校验
  3. 简化EdmFunctionSchema的returnType定义,直接复用EdmMap的自动推导能力,覆盖所有返回值场景

修正后的完整可运行代码:

// Edm原始类型定义,和现有用法对齐
namespace Edm {
  export const String = 'Edm.String' as const;
  // 可按相同方式扩展Number、Boolean等其他原始类型
}

// 基础类型到Edm原始类型的映射
type EdmPrimitiveMap<T> = T extends string ? typeof Edm.String : never;

// 核心Edm类型映射:自动区分数组、基础类型、对象
type EdmMap<T> =
  // 数组类型:映射为元素对应Edm类型的数组
  T extends Array<infer U> ? Array<EdmMap<U>> :
  // 基础类型:映射到对应Edm原始类型
  T extends string | number | boolean ? EdmPrimitiveMap<T> :
  // 对象类型:映射为EdmSchema结构
  T extends object ? EdmSchema<T> :
  never;

type EdmSchemaValue<T> = {
    type: EdmMap<T>;
    nullable?: boolean;
};

// 修正后的EdmSchema:所有属性统一映射为EdmSchemaValue
type EdmSchema<T extends object> = {
  [K in keyof T]: EdmSchemaValue<T[K]>
};

// 补全缺失的工具类型
type UnPromisify<T> = T extends Promise<infer U> ? U : T;
type FunctionWithAgs = (...args: any[]) => any;
type EdmParameterArray<T extends FunctionWithAgs> = Array<{
  type: EdmMap<Parameters<T>[number]>;
  name: string;
  nullable?: boolean;
}>;
type EdmFunctionObject<T> = {
  [K in keyof T]: T[K] extends FunctionWithAgs ? EdmFunctionSchema<T[K]> : never
};

// 修正后的函数Schema定义
type EdmFunctionSchema<T extends FunctionWithAgs, RT = UnPromisify<ReturnType<T>>> = {
    params: EdmParameterArray<T>;
    returnType: EdmMap<RT>;
};

// 测试接口
interface IHostEntry {
  address: string;
  hostname: string;
  aliases: string[];
}

// 无类型报错
const hostDataSchema: EdmSchema<IHostEntry> = {
    address: {type: Edm.String, nullable: false},
    hostname: {type: Edm.String, nullable: false},
    aliases: {type: [Edm.String], nullable: false},
};

interface IFunc {
    list(all: string): Promise<IHostEntry[]>;
}

// 无类型报错,returnType被正确推导为EdmSchema<IHostEntry>[]
const functionSchema: EdmFunctionObject<IFunc> = {
    list: {params: [{type: Edm.String, name: 'all', nullable: false}], returnType: [hostDataSchema]},
};

修正效果
  • hostDataSchema不再抛出缺少type属性的类型错误
  • 数组场景下returnType会被正确推导:当返回值为IHostEntry[]时,returnType类型为EdmSchema<IHostEntry>[],可正确识别[hostDataSchema]为合法值
  • 天然支持嵌套对象、多层数组的类型校验,后续扩展复杂实体类型不会出现匹配逻辑错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 02:18:04