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

如何优化TypeScript过滤器类型定义实现严格校验?

TypeScript 过滤器类型严格校验问题

现有类型定义

// 类型定义
export enum TableFilterType {
    MULTIPLE = 'multiple',
    SINGLE = 'single'
}

export type TableBasePrimaryFilter = {
    type: TableFilterType;
    id: string | number;
    label: string;
    plural: string;
    icon?: string;
    unit?: string;
    iconClass?: Array<string>;
    optionsListWidth?: number;
};

export enum FilterDataLoadOrigin {
    CLIENT = 'CLIENT',
    SERVER = 'SERVER',
}

type TablePrimaryFilterCommon = {
    id: string | number;
    label: string;
    plural: string;
    type: TableFilterType;
};

export type TableMultiplePrimaryFilterClient = TablePrimaryFilterCommon & {
    mode: FilterDataLoadOrigin.CLIENT;
};

export type TableMultiplePrimaryFilterServer = TablePrimaryFilterCommon & {
    mode: FilterDataLoadOrigin.SERVER;
    hasMore: boolean;
    total: number;
};

export type TableMultiplePrimaryFilter = TableMultiplePrimaryFilterClient | TableMultiplePrimaryFilterServer;

export type TableSinglePrimaryFilterClient = TablePrimaryFilterCommon & {
    mode: FilterDataLoadOrigin.CLIENT;
};

export type TableSinglePrimaryFilterServer = TablePrimaryFilterCommon & {
    mode: FilterDataLoadOrigin.SERVER;
    hasMore: boolean;
    total: number;
};

export type TableSinglePrimaryFilter = TableSinglePrimaryFilterClient | TableSinglePrimaryFilterServer;

export type TablePrimaryFilter =
    | TableMultiplePrimaryFilter
    | TableSinglePrimaryFilter

存在的校验漏洞

漏洞1:CLIENT模式下非法属性未触发报错

当mode为FilterDataLoadOrigin.CLIENT时,hasMore和total属于非法属性,但TypeScript未检测到错误:

// 示例
const x: TablePrimaryFilter = {
    id: 'level',
    label: 'label',
    plural: 'plural',
    type: TableFilterType.SINGLE,
    mode: FilterDataLoadOrigin.CLIENT,
    // 注意:以下两行应该触发错误,因为CLIENT模式下不允许hasMore和total
    hasMore: true,
    total: 100,
};

漏洞2:新增NUMBER类型后非法属性未触发报错

新增NUMBER类型过滤器后,当type为TableFilterType.NUMBER时,mode、hasMore、total属于非法属性,但TypeScript未检测到错误:

export enum TableFilterType {
    MULTIPLE = 'multiple',
    SINGLE = 'single',
    NUMBER = 'number',
}

export type TableNumberPrimaryFilter = TablePrimaryFilterCommon & {
    type: TableFilterType.NUMBER
};

export type TablePrimaryFilter =
    | TableMultiplePrimaryFilter
    | TableSinglePrimaryFilter
    | TableNumberPrimaryFilter
// 示例
const x: TablePrimaryFilter = {
    id: 'level',
    label: 'label',
    plural: 'plural',
    type: TableFilterType.NUMBER,
    // 注意:以下行应该触发错误,因为NUMBER类型不允许mode、hasMore和total
    mode: FilterDataLoadOrigin.SERVER,
    hasMore: true,
    total: 100,
};

解决方案

要实现严格的属性校验,需要在联合类型的每个分支中显式排除不需要的属性,通过将这些属性的类型设置为never来禁止它们存在。修改后的类型定义如下:

export enum TableFilterType {
    MULTIPLE = 'multiple',
    SINGLE = 'single',
    NUMBER = 'number',
}

export enum FilterDataLoadOrigin {
    CLIENT = 'CLIENT',
    SERVER = 'SERVER',
}

type TablePrimaryFilterCommon = {
    id: string | number;
    label: string;
    plural: string;
    type: TableFilterType;
    // 公共可选属性
    icon?: string;
    unit?: string;
    iconClass?: Array<string>;
    optionsListWidth?: number;
};

// 多选择器 - CLIENT模式:禁止hasMore和total
export type TableMultiplePrimaryFilterClient = TablePrimaryFilterCommon & {
    type: TableFilterType.MULTIPLE;
    mode: FilterDataLoadOrigin.CLIENT;
    hasMore?: never;
    total?: never;
};

// 多选择器 - SERVER模式:必须有hasMore和total
export type TableMultiplePrimaryFilterServer = TablePrimaryFilterCommon & {
    type: TableFilterType.MULTIPLE;
    mode: FilterDataLoadOrigin.SERVER;
    hasMore: boolean;
    total: number;
};

export type TableMultiplePrimaryFilter = TableMultiplePrimaryFilterClient | TableMultiplePrimaryFilterServer;

// 单选择器 - CLIENT模式:禁止hasMore和total
export type TableSinglePrimaryFilterClient = TablePrimaryFilterCommon & {
    type: TableFilterType.SINGLE;
    mode: FilterDataLoadOrigin.CLIENT;
    hasMore?: never;
    total?: never;
};

// 单选择器 - SERVER模式:必须有hasMore和total
export type TableSinglePrimaryFilterServer = TablePrimaryFilterCommon & {
    type: TableFilterType.SINGLE;
    mode: FilterDataLoadOrigin.SERVER;
    hasMore: boolean;
    total: number;
};

export type TableSinglePrimaryFilter = TableSinglePrimaryFilterClient | TableSinglePrimaryFilterServer;

// 数字过滤器:禁止mode、hasMore和total
export type TableNumberPrimaryFilter = TablePrimaryFilterCommon & {
    type: TableFilterType.NUMBER;
    mode?: never;
    hasMore?: never;
    total?: never;
};

export type TablePrimaryFilter =
    | TableMultiplePrimaryFilter
    | TableSinglePrimaryFilter
    | TableNumberPrimaryFilter;

验证效果

现在再运行之前的错误示例,TypeScript会正确触发报错:

  • CLIENT模式下添加hasMore/total会提示类型不兼容
  • NUMBER类型下添加mode/hasMore/total会提示类型不兼容

这样就实现了严格的属性校验,确保每个过滤器类型只能包含允许的属性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 03:42:18