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

如何为TypeScript中的工厂函数正确添加泛型类型约束?

为Widget工厂函数添加正确的TypeScript类型约束

现有类型与组件定义

interface Widget { type: string; }
interface TextField extends Widget { type: 'TextField'; textValue: string; }
interface Checkbox extends Widget { type: 'Checkbox'; booleanValue: boolean; }

type Props<W extends Widget> = { widget: W; }
type WidgetComponent<W extends Widget> = (props: Props<W>) => React.ReactNode;

const TextfieldComponent: WidgetComponent<TextField> = ({ widget }) => { return <input type="text" /> };
const CheckboxComponent: WidgetComponent<Checkbox> = ({ widget }) => { return <input type="checkbox" />};

类型谓词定义

const isTextfield = (widget: Widget): widget is TextField => widget.type === 'TextField';
const isCheckbox = (widget: Widget): widget is Checkbox => widget.type === 'Checkbox';

待修正的工厂函数及报错

原工厂函数代码:

const factory = <W extends Widget>(widget: W): WidgetComponent<W> | null => {
    if (isTextfield(widget)) {
        return TextfieldComponent;
    } else if (isCheckbox(widget)) {
        return CheckboxComponent;
    }
    return null;
}

报错信息:

Type 'WidgetComponent<TextField>' is not assignable to type 'WidgetComponent<W>'.
  Type 'W' is not assignable to type 'TextField'.
    Property 'textValue' is missing in type 'Widget' but required in type 'TextField'.(2322)

解决方案

方案1:使用函数重载(推荐,类型匹配最直观)

通过重载签名明确输入与输出的类型映射,实现签名处理逻辑:

// 重载签名:定义每种Widget类型对应的返回组件
function factory(widget: TextField): WidgetComponent<TextField>;
function factory(widget: Checkbox): WidgetComponent<Checkbox>;
// 兜底:其他Widget类型返回null
function factory(widget: Widget): null;
// 实现签名
function factory(widget: Widget): WidgetComponent<any> | null {
    if (isTextfield(widget)) {
        return TextfieldComponent;
    } else if (isCheckbox(widget)) {
        return CheckboxComponent;
    }
    return null;
}

方案2:使用条件类型映射

定义条件类型将Widget类型映射到对应的组件类型,配合类型断言消除报错:

// 定义Widget到组件的条件映射类型
type WidgetToComponent<W extends Widget> = 
    W extends TextField ? WidgetComponent<TextField> :
    W extends Checkbox ? WidgetComponent<Checkbox> :
    null;

const factory = <W extends Widget>(widget: W): WidgetToComponent<W> => {
    if (isTextfield(widget)) {
        return TextfieldComponent as WidgetToComponent<W>;
    } else if (isCheckbox(widget)) {
        return CheckboxComponent as WidgetToComponent<W>;
    }
    return null as WidgetToComponent<W>;
}

方案3:改用判别式联合类型优化Widget定义

将Widget改为TextField | Checkbox的联合类型,利用TypeScript的判别式类型推断简化逻辑:

// 先定义具体Widget类型,再组成联合类型
interface TextField { type: 'TextField'; textValue: string; }
interface Checkbox { type: 'Checkbox'; booleanValue: boolean; }
type Widget = TextField | Checkbox;

// 其他类型定义保持不变...

const factory = <W extends Widget>(widget: W): WidgetComponent<W> | null => {
    switch(widget.type) {
        case 'TextField':
            return TextfieldComponent as WidgetComponent<W>;
        case 'Checkbox':
            return CheckboxComponent as WidgetComponent<W>;
        default:
            return null;
    }
}

方案说明

  • 函数重载:类型提示清晰,调用时能精确推断返回值类型,适合Widget类型较少的场景。
  • 条件类型:适合需要动态扩展Widget类型的场景,但需要手动添加类型断言。
  • 判别式联合:是TypeScript处理多态组件场景的最佳实践,能让类型推断更顺畅,减少冗余代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 13:43:19