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

如何为任意项数的逗号分隔字符串创建TypeScript类型?

问题描述

现有一个筛选值对象:

const values = {
  search,
  users,
  categories,
  sorting,
}

需要派生一个名为FilterSelection的字符串类型,合法与非法示例如下:

const exampleFilterSelections = {
  valid: [
    "all",
    "search,users,sorting",
    "-search",
    "-search,-users",
  ], 
  invalid: [
    "any",
    "search,-users",
    "users,users",
    "accounts",
  ]
}

单个选项的类型容易定义:

type IncludedFilter = keyof typeof values
type ExcludedFilter = `-${IncludedFilter}` // 注:原代码中SelectedFilter应为IncludedFilter

目标是定义FilterInclusions和FilterExclusions,从而组合出:

type FilterSelection = FilterInclusions | FilterExclusions | "all"

但当前手动枚举多组合的写法过于繁琐:

type FilterInclusions = 
  | IncludedFilter 
  | `${IncludedFilter},${IncludedFilter}`
  | `${IncludedFilter},${IncludedFilter},${IncludedFilter}`
  // 以此类推...

需要更简洁、非手动的实现方式。


解决方案

可以利用TypeScript的递归条件类型和字符串模板类型实现,同时确保:

  • 仅包含合法筛选键(无未知项)
  • 同一筛选键不重复出现
  • 不会混合包含(无前缀)和排除(带-前缀)的项

步骤1:修正并定义基础类型

// 补全values的实际值(示例用空字符串占位)
const values = {
  search: "",
  users: "",
  categories: "",
  sorting: "",
};

type IncludedFilter = keyof typeof values;
type ExcludedFilter = `-${IncludedFilter}`;

步骤2:定义递归生成无重复组合的辅助类型

// 移除联合类型中的指定项,避免重复
type ExcludeFromUnion<T, U> = T extends U ? never : T;

// 递归生成任意数量的唯一项逗号分隔字符串
type CommaSeparated<T extends string> = 
  | T 
  | `${T},${CommaSeparated<ExcludeFromUnion<T, T>>}`;

步骤3:生成FilterInclusions和FilterExclusions

type FilterInclusions = CommaSeparated<IncludedFilter>;
type FilterExclusions = CommaSeparated<ExcludedFilter>;

步骤4:组合最终的FilterSelection

type FilterSelection = FilterInclusions | FilterExclusions | "all";

效果验证

此时以下场景会被正确校验:

  • 合法:"search"、"users,categories,sorting"、"-sorting,-search"、"all"
  • 非法:"search,-users"(混合包含/排除)、"users,users"(重复项)、"accounts"(未知项)、"any"(非法关键字)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 11:05:21