TypeScript如何根据泛型对象控制属性的必填/可选/隐藏
TypeScript 泛型控制属性必填/可选/隐藏解决方案
需求说明
根据泛型对象中是否显式定义payload属性类型,控制Action类型的payload属性:
- 未显式指定
payload时,该属性不可传有效值(或仅允许undefined) - 显式指定
payload类型时,该属性强制必填
原代码及问题
原代码存在语法错误(ActionBaseType缺少=),且无法实现需求:
// 修正前的基础类型(存在语法错误) type ActionBaseType { payload?: any extra?: any } // 原Action类型定义,无法区分payload是否被显式指定 type Action<ActionType extends ActionBaseType = ActionBaseType> = { extra?: ActionType['extra'] payload?: ActionType['payload'] } // 期望:未指定payload,payload应不可传或可选 const action: Action<{extra: number}> = {extra: 1} // 期望:指定了payload类型,需强制传入payload const action: Action<{extra: number, payload: {id: number}}> = {extra: 1, payload: {id: 2}}
尝试过的无效写法
以下两种写法均未生效,原因是泛型约束导致ActionType始终继承ActionBaseType的payload属性,无法判断是否显式指定:
// 写法一:通过类型判断控制payload,无效 type Action<ActionType extends ActionBaseType = ActionBaseType> = { extra?: ActionType['extra'] payload?: ActionType['payload'] extends never ? undefined : ActionType['payload'] } // 写法二:通过交叉类型控制,无效 type Action<ActionType extends ActionBaseType = ActionBaseType> = { extra?: ActionType['extra'] } & (ActionType['payload'] extends never ? {} : {payload: ActionType['payload']})
正确解决方案
调整泛型约束逻辑,通过条件类型判断ActionType是否显式定义payload,从而控制属性的必填性:
// 修正后的基础类型 type ActionBaseType = { payload?: any extra?: any } // 最终Action类型定义 type Action<ActionType extends { payload?: any; extra?: any } = ActionBaseType> = { extra?: ActionType['extra'] } & (ActionType extends { payload: infer P } ? { payload: P } // 显式指定payload,设为必填 : { payload?: never }) // 未指定payload,仅允许undefined或不传
验证示例
// 未指定payload:仅允许传extra,payload不可传有效值 const validAction1: Action<{ extra: number }> = { extra: 1 } const invalidAction1: Action<{ extra: number }> = { extra: 1, payload: 2 } // 类型报错 // 指定payload:必须传入符合类型的payload const validAction2: Action<{ extra: number; payload: { id: number } }> = { extra: 1, payload: { id: 2 } } const invalidAction2: Action<{ extra: number; payload: { id: number } }> = { extra: 1 } // 类型报错
内容的提问来源于stack exchange,提问作者Oki
相关产品推荐
相关产品推荐

