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

TypeScript:如何将函数返回类型索引指定为M的字符串类型?

TypeScript映射函数类型断言报错解决

问题场景

原TypeScript函数如下:

export const mappingResult = <
  const M extends Record<keyof T, string>,
  T extends Record<string, null | string | number | boolean>
>(
  schema: M,
  input: T
) => {
  return Object.keys(input).reduce(
    (acc, key) => {
      const val = schema[key];
      const inputValue = input[key];
      if (val) {
        acc[val] = inputValue;
      }
      return acc;
    },
    {} as { [K: string]: null | string | number | boolean }
  );
};

需求是将初始值的索引类型string替换为泛型M中定义的字符串类型,尝试了以下类型断言:

{} as { [K in keyof T as M[K]]: null | string | number | boolean }

但此时acc[val]出现报错,中文翻译为:

找不到参数类型为'string'的索引签名,该类型为'{ [K in keyof T as M[K]]: string | number | boolean | null; }'

解决方法

原因分析

报错核心是TypeScript无法自动推断schema[key](即val)的类型就是目标对象的键类型——Object.keys(input)返回的是string[]而非(keyof T)[],导致schema[key]被宽泛推断为string,无法匹配映射后的具体键类型。

方案一:类型断言缩小val的范围

先定义结果类型别名简化代码,再将val断言为结果类型的键:

export const mappingResult = <
  const M extends Record<keyof T, string>,
  T extends Record<string, null | string | number | boolean>
>(
  schema: M,
  input: T
) => {
  // 定义结果类型别名
  type ResultType = { [K in keyof T as M[K]]: null | string | number | boolean };
  return Object.keys(input).reduce(
    (acc, key) => {
      // 将val断言为ResultType的键类型
      const val = schema[key] as keyof ResultType;
      const inputValue = input[key];
      if (val) {
        acc[val] = inputValue;
      }
      return acc;
    },
    {} as ResultType
  );
};

方案二:优化key的类型并关联结果键

先把Object.keys的返回值断言为keyof T数组,再将val断言为结果类型的键,提升类型精确性:

export const mappingResult = <
  const M extends Record<keyof T, string>,
  T extends Record<string, null | string | number | boolean>
>(
  schema: M,
  input: T
) => {
  type ResultType = { [K in keyof T as M[K]]: null | string | number | boolean };
  // 将Object.keys结果断言为keyof T数组
  return (Object.keys(input) as Array<keyof T>).reduce(
    (acc, key) => {
      const val = schema[key];
      const inputValue = input[key];
      if (val) {
        acc[val as keyof ResultType] = inputValue;
      }
      return acc;
    },
    {} as ResultType
  );
};

方案三:用Record直接定义结果类型

更直观的方式是直接提取M中所有值的类型作为结果对象的键,用Record定义类型:

export const mappingResult = <
  const M extends Record<keyof T, string>,
  T extends Record<string, null | string | number | boolean>
>(
  schema: M,
  input: T
) => {
  // 提取M中所有值的类型作为结果键
  type ResultKeys = M[keyof T];
  type ResultType = Record<ResultKeys, null | string | number | boolean>;
  return (Object.keys(input) as Array<keyof T>).reduce(
    (acc, key) => {
      const val = schema[key];
      const inputValue = input[key];
      if (val) {
        acc[val] = inputValue;
      }
      return acc;
    },
    {} as ResultType
  );
};

这个方案中,ResultKeys直接对应M里的所有映射键类型,TypeScript能自动识别val属于ResultKeys,无需额外断言(若Object.keys未断言为keyof T,可能仍需对val做断言)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 18:32:37