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

TypeScript条件语句无法过滤类型值?求有效解决方案

TypeScript条件类型约束错误的解决方案

问题描述

我在使用TypeScript条件语句时遇到类型过滤失效的问题:当ErrorsType同时包含函数和字符串类型的值时,使用ErrorsType[T] extends Function ? Parameters<ErrorsType[T]> : []的条件判断,TypeScript无法正确收缩类型,导致构造函数的args参数出现约束错误:

Type 'Function & { test: (reason: string) => string; ValueTooLow: string; }[T]' does not satisfy the constraint '(...args: any) => any'

我的代码如下:

export const BotErrors = {
    test: (reason: string) => `This error bc of ${reason}`,
    ValueTooLow: 'You can not reduce value below 0',
};

type ErrorsType = typeof BotErrors;

export default class SomeError<T extends keyof ErrorsType> extends Error {
    constructor(code: T, ...args: ErrorsType[T] extends Function ? Parameters<ErrorsType[T]> : []) {
        let msg: string | Function = BotErrors[code];
        if (typeof msg === 'function') msg = msg(...args) as string;
        super(msg);
    }
}

添加// @ts-nocheck能暂时绕过错误,但我希望找到不忽略错误的正规解决办法。

解决方法

方法一:用Extract工具类型精准提取函数类型

问题核心是TypeScript在泛型上下文无法自动确认ErrorsType[T]是函数类型,导致Parameters工具类型收到不符合约束的输入。用Extract工具类型从ErrorsType[T]中提取出函数类型,就能让Parameters正常工作:

export default class SomeError<T extends keyof ErrorsType> extends Error {
    constructor(code: T, ...args: ErrorsType[T] extends Function ? Parameters<Extract<ErrorsType[T], Function>> : []) {
        let msg: string | Function = BotErrors[code];
        if (typeof msg === 'function') {
            msg = msg(...(args as Parameters<typeof msg>)) as string;
        }
        super(msg);
    }
}

方法二:给构造函数定义重载

如果觉得上面的写法繁琐,直接给构造函数定义重载,分别处理需要参数和不需要参数的错误码,TS会精准识别不同错误码对应的参数要求:

export default class SomeError<T extends keyof ErrorsType> extends Error {
    // 重载:处理需要参数的错误码
    constructor(code: 'test', reason: string);
    // 重载:处理不需要参数的错误码
    constructor(code: 'ValueTooLow');
    // 构造函数实现
    constructor(code: T, ...args: any[]) {
        let msg: string | Function = BotErrors[code];
        if (typeof msg === 'function') {
            msg = msg(...args);
        }
        super(msg as string);
    }
}

方法三:重构错误类型定义(扩展性更强)

如果后续需要新增更多错误码,可以提前定义清晰的联合类型,让TS能更好地推导类型:

// 定义每个错误的结构类型
type BotErrorDef = 
    | { code: 'test', handler: (reason: string) => string }
    | { code: 'ValueTooLow', message: string };

// 用satisfies确保错误对象符合定义
export const BotErrors = {
    test: (reason: string) => `This error bc of ${reason}`,
    ValueTooLow: 'You can not reduce value below 0',
} satisfies Record<BotErrorDef['code'], any>;

type ErrorsType = typeof BotErrors;

export default class SomeError<T extends BotErrorDef['code']> extends Error {
    constructor(
        code: T, 
        ...args: Extract<BotErrorDef, { code: T }> extends { handler: infer F } ? Parameters<F> : []
    ) {
        const def = BotErrors[code];
        const msg = typeof def === 'function' ? def(...args) : def;
        super(msg);
    }
}

这种方式新增错误码时,只需在BotErrorDef中添加对应的结构即可,维护性更强。

内容的提问来源于stack exchange,提问作者Bill.zhanxg

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 16:01:28