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

TypeScript接口条件属性配置:按需必填属性实现方案咨询

条件式必填Props的TypeScript实现方案

我正在开发一个根据页面动态切换区块的组件,当前定义的Props接口如下:

interface Props {
  heading: string;
  description: string;
  signUp?: boolean;
  signUpButton1?: string;
  signUpButtonLink1?: string;
  signUpButton2?: string;
  signUpButtonLink2?: string;
  startFreeAccount?: boolean;
  startFreeAccountSignUpButton?: string;
  startFreeAccountLink1?: string;
  startFreeAccountSignUpLink1?: string;
  startFreeAccountSignUpLink2?: string;
  startFreeAccountSignUpLink3?: string;
  contactUsForDemo?: boolean;
  contactUsForDemoInput1?: string;
  contactUsForDemoInput2?: string;
  contactUsForDemoInput3?: string;
  contactUsForDemoButtonText?: string;
  ThanksForDemo?: boolean;
  ThanksForDemoButton?: string;
} 

代码里通过props.signUp &&渲染对应区块,但遇到两个矛盾的问题:

  • Next.js的Link组件无法接收undefined类型的链接属性
  • 如果把这些关联属性设为必填,即使不启用signUp区块,也必须传入对应值,不符合动态切换的逻辑

需要实现的效果是:当某个布尔开关(比如signUp === true)启用时,对应的关联属性(signUpButton1、signUpButtonLink1等)必须赋值;开关关闭或不填时,这些属性无需传入。


解决方案:用TypeScript联合类型实现条件校验

核心思路是把Props拆分为基础必填属性和各区块的启用/关闭子类型,再通过联合类型组合,让TypeScript自动校验不同场景下的属性必填性。

1. 拆分基础属性与各区块的子类型

先定义所有场景都需要的基础属性,再分别定义每个区块启用/关闭时的属性规则:

// 所有场景都必填的基础属性
interface BaseProps {
  heading: string;
  description: string;
}

// SignUp区块启用时的属性:开关为true,关联必填属性设为必填
interface SignUpEnabledProps {
  signUp: true;
  signUpButton1: string;
  signUpButtonLink1: string;
  signUpButton2?: string; // 可选属性保持原规则
  signUpButtonLink2?: string;
}

// SignUp区块关闭时的属性:开关为false/不填,关联属性设为never(禁止传入)
interface SignUpDisabledProps {
  signUp?: false;
  signUpButton1?: never;
  signUpButtonLink1?: never;
  signUpButton2?: never;
  signUpButtonLink2?: never;
}

// StartFreeAccount区块的启用/关闭类型
interface StartFreeAccountEnabledProps {
  startFreeAccount: true;
  startFreeAccountSignUpButton: string;
  startFreeAccountLink1: string;
  startFreeAccountSignUpLink1: string;
  startFreeAccountSignUpLink2: string;
  startFreeAccountSignUpLink3: string;
}

interface StartFreeAccountDisabledProps {
  startFreeAccount?: false;
  startFreeAccountSignUpButton?: never;
  startFreeAccountLink1?: never;
  startFreeAccountSignUpLink1?: never;
  startFreeAccountSignUpLink2?: never;
  startFreeAccountSignUpLink3?: never;
}

// ContactUsForDemo区块的启用/关闭类型
interface ContactUsForDemoEnabledProps {
  contactUsForDemo: true;
  contactUsForDemoInput1: string;
  contactUsForDemoInput2: string;
  contactUsForDemoInput3: string;
  contactUsForDemoButtonText: string;
}

interface ContactUsForDemoDisabledProps {
  contactUsForDemo?: false;
  contactUsForDemoInput1?: never;
  contactUsForDemoInput2?: never;
  contactUsForDemoInput3?: never;
  contactUsForDemoButtonText?: never;
}

// ThanksForDemo区块的启用/关闭类型
interface ThanksForDemoEnabledProps {
  ThanksForDemo: true;
  ThanksForDemoButton: string;
}

interface ThanksForDemoDisabledProps {
  ThanksForDemo?: false;
  ThanksForDemoButton?: never;
}

2. 组合成最终的Props类型

通过交叉类型(&)将基础属性与各区块的联合类型(|)组合:

type Props = BaseProps & 
  (SignUpEnabledProps | SignUpDisabledProps) &
  (StartFreeAccountEnabledProps | StartFreeAccountDisabledProps) &
  (ContactUsForDemoEnabledProps | ContactUsForDemoDisabledProps) &
  (ThanksForDemoEnabledProps | ThanksForDemoDisabledProps);

效果说明

  • 当你设置signUp: true时,TypeScript会强制要求传入signUpButton1和signUpButtonLink1,避免undefined传入Link组件
  • 当signUp设为false或不填时,无法传入signUpButton1等关联属性(传入会触发类型报错),符合动态切换的逻辑
  • 其他区块的布尔开关和关联属性会遵循同样的校验规则

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 09:56:21