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

如何在TypeScript中无类型转换地实现类型安全的带标记对象转换?

类型安全创建带标记对象的解决方案

你当前的实现用any绕过了TypeScript的类型检查,存在类型不安全的隐患。以下是几种优化方案,能让你在类型安全的前提下构建TaggedObject<T>:

方案一:Partial初始化 + 精准类型断言

将结果对象初始化为Partial<TaggedObject<T>>,让TypeScript跟踪每个键的类型,最后断言为完整类型(我们确保所有键都会被处理):

const createTaggedObject = <T extends object>(input: T): TaggedObject<T> => {
  const result: Partial<TaggedObject<T>> = {};

  for (const key in input) {
    if (input.hasOwnProperty(key)) {
      const value = input[key];
      if (typeof value === "string") {
        result[key] = { type: "string", value } as TaggedType<T[typeof key]>;
      } else if (typeof value === "number") {
        result[key] = { type: "number", value } as TaggedType<T[typeof key]>;
      } else if (typeof value === "boolean") {
        result[key] = { type: "boolean", value } as TaggedType<T[typeof key]>;
      }
    }
  }

  return result as TaggedObject<T>;
};

方案二:拆分单个值标记逻辑为辅助函数

用泛型辅助函数处理单个值的标记,让TypeScript更精准地推断类型,避免直接断言整个对象:

const tagValue = <T extends string | number | boolean>(value: T): TaggedType<T> => {
  switch (typeof value) {
    case "string":
      return { type: "string", value } as TaggedType<T>;
    case "number":
      return { type: "number", value } as TaggedType<T>;
    case "boolean":
      return { type: "boolean", value } as TaggedType<T>;
    default:
      throw new Error(`不支持的类型: ${typeof value}`);
  }
};

const createTaggedObject = <T extends { [K in keyof T]: string | number | boolean }>(input: T): TaggedObject<T> => {
  const result: Partial<TaggedObject<T>> = {};

  for (const key in input) {
    if (input.hasOwnProperty(key)) {
      result[key] = tagValue(input[key]);
    }
  }

  return result as TaggedObject<T>;
};

方案三:自定义类型守卫强化类型检查

通过自定义类型守卫函数,让TypeScript明确每个分支中值的类型,进一步提升类型安全性:

function isString(value: unknown): value is string {
  return typeof value === "string";
}

function isNumber(value: unknown): value is number {
  return typeof value === "number";
}

function isBoolean(value: unknown): value is boolean {
  return typeof value === "boolean";
}

const createTaggedObject = <T extends object>(input: T): TaggedObject<T> => {
  const result: Partial<TaggedObject<T>> = {};

  for (const key in input) {
    if (input.hasOwnProperty(key)) {
      const value = input[key];
      if (isString(value)) {
        result[key] = { type: "string", value };
      } else if (isNumber(value)) {
        result[key] = { type: "number", value };
      } else if (isBoolean(value)) {
        result[key] = { type: "boolean", value };
      }
    }
  }

  return result as TaggedObject<T>;
};

关键说明

  • 用Partial<TaggedObject<T>>初始化结果,避免any导致的类型丢失。
  • 最终的as TaggedObject<T>断言是安全的,因为我们遍历了输入对象的所有自有属性,且只处理string/number/boolean类型的属性。
  • 若要处理其他类型属性,可添加错误逻辑,避免生成不符合类型定义的结果。

内容的提问来源于stack exchange,提问作者lentil-soup

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 02:14:59