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

如何在不使用类型断言的情况下编写类型安全的TypeScript stringifyQuery函数

问题分析

TypeScript 报错的核心原因是:Object.entries(query) 返回的类型是 Array<[string, T[keyof T]]>,经过 map 转换后得到 Array<[string, string]>,而 Object.fromEntries 会将其推断为 { [k: string]: string }——这是一个键为任意字符串的对象类型,但我们的返回类型要求是与输入对象 T 的键完全对应的映射类型 { [K in keyof T]: string },两者类型不兼容。

下面提供几种无需使用不安全类型断言的解决方案:

方案一:手动遍历键并赋值

通过将 Object.keys 的结果转换为 keyof T 类型数组(这是安全的,因为 T 的键必然是字符串子集),逐个赋值确保类型匹配:

function stringifyQuery<T extends Record<string, unknown>>(query: T): { [K in keyof T]: string } {
  const result = {} as { [K in keyof T]: string };
  const keys = Object.keys(query) as readonly (keyof T)[];
  
  for (const key of keys) {
    result[key] = JSON.stringify(query[key]);
  }
  
  return result;
}

方案二:使用 reduce 约束类型

利用 reduce 逐步构建结果对象,同时明确键的类型转换:

function stringifyQuery<T extends Record<string, unknown>>(query: T): { [K in keyof T]: string } {
  return Object.keys(query).reduce((acc, key) => {
    const typedKey = key as keyof T;
    acc[typedKey] = JSON.stringify(query[typedKey]);
    return acc;
  }, {} as { [K in keyof T]: string });
}

方案三:封装类型安全的 fromEntries

如果需要复用类似的类型转换逻辑,可以先封装一个保留键类型的 fromEntries 工具函数:

// 定义保留键具体类型的对象条目类型
type ObjectEntries<T> = { [K in keyof T]: [K, T[K]] }[keyof T][];

function typeSafeFromEntries<T extends Record<string, unknown>>(entries: ObjectEntries<T>): T {
  return Object.fromEntries(entries) as T;
}

function stringifyQuery<T extends Record<string, unknown>>(query: T): { [K in keyof T]: string } {
  const stringEntries = (Object.entries(query) as ObjectEntries<T>).map(
    ([key, value]) => [key, JSON.stringify(value)] as const
  );
  
  return typeSafeFromEntries(stringEntries);
}

以上方案中出现的类型转换均为基于已知类型关系的安全转换,而非随意的类型断言,既满足了编译时的类型安全要求,也保证了运行时的行为符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 05:53:23