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

构建并类型化富搜索对象的TypeScript类型问题求助

解决方案:自动推导搜索对象类型与重命名映射

以下是针对你遇到的四个类型问题的具体TypeScript实现方案,完全基于泛型、工具类型与Zod的类型提取能力解决:

1. 先定义releaseConditions的强制类型约束

通过基础类型强制要求返回结构必须包含include和exclude,且两者的字段结构一致:

import z from 'zod';

// 单个搜索条件的Schema结构:键为原始搜索字段名,值为Zod校验规则
type ConditionSchema = Record<string, z.ZodTypeAny>;

// 约束releaseConditions必须返回包含include/exclude的对象,且两者字段匹配
type ReleaseConditions<T extends ConditionSchema> = {
  include: T;
  exclude: T;
};

2. 实现自动重命名+类型推断的核心逻辑

通过泛型工具类型完成字段重命名映射,同时从Zod Schema中自动提取属性类型:

import parse from 'search-query-parser';

// 工具类型:定义原始字段到目标属性名的映射规则
type RenameMap<T extends ConditionSchema> = {
  [K in keyof T]: string;
};

// 工具类型:从条件Schema和重命名映射中推导最终搜索对象的类型
type ParsedSearchResult<
  T extends ConditionSchema,
  R extends RenameMap<T>
> = {
  // 自动将原始字段名重命名为目标属性名,并提取Zod对应的类型
  [K in keyof T as R[K]]: z.infer<T[K]>;
} & {
  // 保留原始keywords数组(根据需求可调整)
  keywords?: string[];
};

// 核心处理函数:整合解析、重命名、类型校验
function processSearchQuery<
  T extends ConditionSchema,
  R extends RenameMap<T>
>(
  rawQuery: string,
  renameMap: R,
  releaseConditions: ReleaseConditions<T>
): ParsedSearchResult<T, R> {
  // 调用search-query-parser解析原始字符串
  const parsedRaw = parse(rawQuery, {
    keywords: Object.keys(releaseConditions.include),
    ranges: [], // 根据你的业务需求配置range规则
  });

  const result: Partial<ParsedSearchResult<T, R>> = {};

  // 处理include条件:自动重命名+Zod类型校验
  Object.entries(releaseConditions.include).forEach(([rawKey, schema]) => {
    const targetKey = renameMap[rawKey as keyof T];
    if (parsedRaw[rawKey]) {
      result[targetKey] = schema.parse(parsedRaw[rawKey]);
    }
  });

  // 处理exclude条件(示例:以exclude_前缀存储,可根据需求调整)
  Object.entries(releaseConditions.exclude).forEach(([rawKey, schema]) => {
    const targetKey = `exclude_${renameMap[rawKey as keyof T]}`;
    if (parsedRaw[`-${rawKey}`]) {
      result[targetKey as keyof ParsedSearchResult<T, R>] = schema.parse(parsedRaw[`-${rawKey}`]);
    }
  });

  // 保留原始keywords
  if (parsedRaw.keywords) {
    result.keywords = parsedRaw.keywords;
  }

  return result as ParsedSearchResult<T, R>;
}

3. 使用示例(自动补全+类型推断生效)

// 定义你的搜索条件Schema
const searchConditions: ReleaseConditions<{
  title: z.ZodString;
  year: z.ZodNumber;
  rating: z.ZodNumber;
}> = {
  include: {
    title: z.string(),
    year: z.number(),
    rating: z.number(),
  },
  exclude: {
    title: z.string(),
    year: z.number(),
    rating: z.number(),
  },
};

// 定义一次重命名映射即可
const renameMap = {
  title: 'movieTitle',
  year: 'releaseYear',
  rating: 'imdbRating',
} as const;

// 处理搜索字符串
const searchResult = processSearchQuery(
  'title:"Inception" year:2010 -rating:<7',
  renameMap,
  searchConditions
);

// 此时searchResult会自动补全属性:movieTitle、releaseYear、imdbRating、exclude_movieTitle等
// 属性类型分别为string、number、number、string等,完全自动推断

对应解决你的四个问题

  • 问题1(自动重命名):仅需维护一份renameMap,通过类型重映射自动完成字段名转换,无需手动重复处理
  • 问题2(属性自动补全):ParsedSearchResult类型会根据重命名映射生成目标属性名,编辑器会自动触发补全
  • 问题3(类型自动推断):通过z.infer<T[K]>从Zod Schema中提取类型,替代unknown
  • 问题4(releaseConditions约束):ReleaseConditions类型强制要求返回包含include/exclude,且两者字段结构一致,结合重命名映射确保属性名匹配

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 04:57:20