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

如何创建含动态字符串键与特定固定键的TypeScript对象类型?

如何定义兼容通用字符串键与特定特殊键的TypeScript类型?

背景

我正在开发一个可动态生成GraphQL查询过滤器的应用,需要创建一个符合过滤器允许结构的TypeScript类型。

需求

所需的TypeScript类型需满足:

  • 所有普通字符串键对应值为类型A(示例中为string)
  • 仅特定键(如"AND"和"OR")对应值为不同类型B(示例中为过滤器数组)

符合要求的过滤器示例

let filter = {
    "fieldA": "2015-10-08",
    "fieldB": "This is the search input string...",
    OR: [
        {"fieldC1": "deleted"},
        { AND: [
            {"fieldD": "null"},
            {"fieldE": "inactive"}
        ]}
    ],
}

尝试过的无效方案

方案一:索引签名与显式属性直接交集

type CustomTypeBase = {
  [key: string]: string;
} & {
  AND?: Array<{[key: string]: string} | CustomTypeBase>;
  OR?: Array<{[key: string]: string} | CustomTypeBase>;
};

问题:TypeScript会强制所有字符串键(包括"AND"和"OR")的值都必须是string类型,与显式属性的类型冲突,导致类型无效。

方案二:使用Omit工具类型

type CustomTypeWithOmit = Omit<{
  [key: string]: string;
}, 'AND' | 'OR'> & {
  AND?: Array<{[key: string]: string} | CustomTypeWithOmit>;
  OR?: Array<{[key: string]: string} | CustomTypeWithOmit>;
};

问题:Omit仅能处理对象的具名属性,无法作用于string这种通用索引签名,因此无法剔除AND/OR键的索引约束,类型仍无效。

核心问题

是否存在一种TypeScript类型定义方式,能让所有普通字符串键对应类型A,仅特定键对应类型B?

解决方案

可以通过映射类型+显式属性交集的方式实现需求,具体类型定义如下:

type Filter = {
  [K in string]: K extends 'AND' | 'OR' ? never : string;
} & {
  AND?: Filter[];
  OR?: Filter[];
};

原理说明

  1. 映射类型{ [K in string]: K extends 'AND' | 'OR' ? never : string }定义了:
    • 所有字符串键中,若键名是AND或OR,则值类型为never(表示这类键不允许通过索引签名赋值)
    • 其余普通字符串键的值类型必须为string
  2. 与包含AND/OR显式属性的对象类型取交集后,TypeScript会优先使用显式属性的类型定义,因此AND/OR键的值类型会被覆盖为Filter[] | undefined,完美满足需求。

验证示例

使用上述类型后,示例中的过滤器对象可以通过类型检查:

let filter: Filter = {
    "fieldA": "2015-10-08",
    "fieldB": "This is the search input string...",
    OR: [
        {"fieldC1": "deleted"},
        { AND: [
            {"fieldD": "null"},
            {"fieldE": "inactive"}
        ]}
    ],
}; // 类型检查通过

通用泛型版本

如果需要支持自定义字段值类型和操作符值类型,可以封装为泛型:

type GenericFilter<FieldValue = string, OperatorValue = GenericFilter<FieldValue>[]> = {
  [K in string]: K extends 'AND' | 'OR' ? never : FieldValue;
} & {
  AND?: OperatorValue;
  OR?: OperatorValue;
};

// 使用示例:定义字段值为数字的过滤器
type NumberFilter = GenericFilter<number>;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 11:05:17