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

如何为jsonCasingParser函数实现参数依赖的返回类型收窄

实现带自动类型收窄的对象键命名格式转换函数

首先补充原代码中缺失的正则表达式常量(否则无法正常运行):

const CAMEL_CASE_PATTERN = /([a-z])([A-Z])/g;
const SNAKE_CASE_PATTERN = /([a-z])_([a-z])/g;
const JSON_VARIABLE_PATTERN = /"(.*?)"/g; // 匹配JSON字符串中的键名

定义键名类型转换工具

要实现返回类型自动收窄,需要先定义TypeScript工具类型来处理键名的类型转换:

// 将蛇形键转换为驼峰键的类型工具
type SnakeToCamelCase<S extends string> = 
  S extends `${infer Prefix}_${infer First}${infer Suffix}`
    ? `${Prefix}${Uppercase<First>}${SnakeToCamelCase<Suffix>}`
    : S;

// 将驼峰键转换为蛇形键的类型工具
type CamelToSnakeCase<S extends string> = 
  S extends `${infer Prefix}${infer First}${infer Suffix}`
    ? `${Prefix}${Lowercase<First>}${First extends Uppercase<First> ? '_' : ''}${CamelToSnakeCase<Suffix>}`
    : S;

// 递归转换对象所有层级键的类型
type TransformKeys<T, Transform extends (key: string) => string> =
  T extends object
    ? {
        [K in keyof T as Transform extends (key: infer U) => infer R ? U extends K ? R : never : never]:
          T[K] extends object ? TransformKeys<T[K], Transform> : T[K]
      }
    : T;

修改核心函数实现(带类型收窄)

通过函数重载+泛型条件类型,让jsonCasingParser根据输入自动匹配返回类型:

export enum CasingPattern {
  SNAKE,
  CAMEL,
}

export const toSnakeCase = (camelCased: string) => {
  const replaced = camelCased.replace(
    new RegExp(CAMEL_CASE_PATTERN, 'g'),
    (match) => {
      const arr = match.split('');
      const last = arr.pop();
      const parsed = arr.join('') + '_' + last?.toLowerCase();
      return parsed;
    },
  );

  return replaced;
};

export const toCamelCase = (snakeCased: string) => {
  const replaced = snakeCased.replace(
    new RegExp(SNAKE_CASE_PATTERN, 'g'),
    (match) => {
      const [lastLetter, firstLetter] = match.split('_');
      const capitalize = firstLetter.toUpperCase();
      return lastLetter + capitalize;
    },
  );

  return replaced;
};

// 函数重载:明确不同输入对应的返回类型
export function jsonCasingParser(jsonPayload: string, targetPattern: CasingPattern): string;
export function jsonCasingParser<T extends object>(jsonPayload: T, targetPattern: CasingPattern.CAMEL): TransformKeys<T, typeof toCamelCase>;
export function jsonCasingParser<T extends object>(jsonPayload: T, targetPattern: CasingPattern.SNAKE): TransformKeys<T, typeof toSnakeCase>;

// 函数实现
export function jsonCasingParser(
  jsonPayload: unknown,
  targetPattern: CasingPattern,
): unknown {
  const isString = typeof jsonPayload === 'string';
  const stringified = isString ? jsonPayload : JSON.stringify(jsonPayload);

  const replaced = stringified.replace(
    new RegExp(JSON_VARIABLE_PATTERN, 'g'),
    (match) => {
      // 先去掉键名的引号再处理,避免引号被误转换
      const key = match.slice(1, -1);
      let transformedKey = key;
      if (targetPattern === CasingPattern.SNAKE) {
        transformedKey = toSnakeCase(key);
      } else if (targetPattern === CasingPattern.CAMEL) {
        transformedKey = toCamelCase(key);
      }
      return `"${transformedKey}"`;
    },
  );

  if (isString) {
    return replaced;
  }

  return JSON.parse(replaced);
}

类型验证示例

// 返回 string 类型
const strResult = jsonCasingParser('{ "propOne": "one" }', CasingPattern.CAMEL);

// 返回 { prop_one: string } 类型
const snakeResult = jsonCasingParser({ propOne: "one" }, CasingPattern.SNAKE);

// 返回 { propOne: string } 类型
const camelResult = jsonCasingParser({ prop_one: "one" }, CasingPattern.CAMEL);

关键说明

  1. 工具类型:通过SnakeToCamelCase和CamelToSnakeCase实现字符串键名的类型映射,TransformKeys递归处理嵌套对象的键类型转换。
  2. 函数重载:明确不同输入参数组合对应的返回类型,让TypeScript自动收窄返回值的类型推断结果。
  3. 实现调整:优化了正则替换逻辑,先剥离键名的引号再处理,避免引号被错误转换。

内容的提问来源于stack exchange,提问作者Cristian Flórez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 10:23:16