在接口中的条件属性

huangapple go评论58阅读模式
英文:

Conditional props in intreface

问题

我有一个关于接口的问题:

基本上,我正在创建一个动态组件,它根据所在的页面而变化。我的接口构建如下:

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 && 
  <div className="mt-10 flex flex-col  items-center gap-x-6">
    <Link
      href={"/signUpPractitioner/startFreeAccount"}
      className="bg-black mb-4 -ml-[14vw] px-16 py-1.5 text-base font-semibold leading-7 text-white shadow-sm  outline outline-offset-0 outline-black"
    >
      {props.signUpButton1}
    </Link>
    <Link href={"/practitioner/contactUsForDemo"} 
      className="bg-white -ml-[14vw] px-10 py-1.5 text-base font-semibold leading-7 text-black outline outline-offset-0 outline-black	 shadow-sm"
    >
      {props.signUpButton2} <span aria-hidden="true">→</span>
    </Link>
  </div>
}

设置 "signUp == true" 将显示组件上面部分的信息。我的问题是,Link(来自NEXTJS)无法处理 "signUpButtonLink1" 可能未定义的情况。如果我要求 "signUpButtonLink1" 必须有一个值,那么即使我不使用组件的 "signUp" 部分,我仍然需要为 "signUpButtonLink1" 赋予某个值,这显然是没有意义的(从当前接口构建的角度来看是有意义的,但从功能角度来看不合理)。

我的问题是:是否可以设置 "signUpButton1、signUpLink1等等" 只需要在 "signUp === true" 的情况下设置?对于接口中的所有布尔值和与之相关的 props 都适用相同的规则。

感谢您的帮助!

英文:

I have a question regarding interfaces:

Basically I'm creating a dynamic component that change depending on which page it is. My interface is constructed like so:

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;
} 

In my code I then use for example:

{props.signUp &amp;&amp; 
          &lt;div className=&quot;mt-10 flex flex-col  items-center gap-x-6&quot;&gt;
            &lt;Link
              href={&quot;/signUpPractitioner/startFreeAccount&quot;}
              className=&quot; bg-black mb-4 -ml-[14vw] px-16 py-1.5 text-base font-semibold leading-7 text-white shadow-sm  outline outline-offset-0 outline-black&quot;
            &gt;
              {props.signUpButton1}
              
            &lt;/Link&gt;
            &lt;Link href={&quot;/practitioner/contactUsForDemo&quot;} 
            className=&quot; bg-white -ml-[14vw] px-10 py-1.5 text-base font-semibold leading-7 text-black outline outline-offset-0 outline-black	 shadow-sm&quot;
&gt;
               {props.signUpButton2} &lt;span aria-hidden=&quot;true&quot;&gt;→&lt;/span&gt;
            &lt;/Link&gt;
          &lt;/div&gt; }

Setting "signUp == true" would display the information in the above part of the component. My issue is that Link (from NEXTJS) cannot handle the fact that "signUpButtonLink1" might be undefined. If I put that "signUpButtonLink1" has to have a value, then even if I don't use the "signUp" part of the component, I still need to assign some value to "signUpButtonLink1" which obviously doesnt make sense (it makes sense in terms of how the current interface is constructed but not in terms of functionality).

My question is: Is it possible to set that "signUpButton1, signUpLink1 etc etc" only needs to be set if "signUp === true" ? It the same for all bools in the interface and the props "affiliated" with it.

Thanks for your help!

答案1

得分: 1

你可以使用简单的联合类型来实现这个。

```ts
type Props = {
  heading: string;
  description: string;
} & (
  | {
      signUp?: false
      signUpButton1?: never
      // ...
    }
  | {
      signUp: true
      signUpButton1: string
      // ...
    }
) & (
  | {
    startFreeAccount?: false;
    startFreeAccountSignUpButton?: never;
    // ...
  }
  | {
    startFreeAccount: true;
    startFreeAccountSignUpButton: string;
    // ...
  }
) & (
  ...
)

也许可以添加一个实用类型:

type OptionalProps<K extends string, T> = 
  | { [key in K]?: false } & { [key in keyof T]?: never }
  | { [key in K]: true } & T

type Props = {
  heading: string
  description: string
}
  & OptionalProps<'signUp', {
    signUpButton1: string,
  }>
  & OptionalProps<'startFreeAccount', {
    startFreeAccountSignUpButton: string
  }>
  & ...

具有 ?: never 的属性并不是必需的,但如果你将 props 解构为单独的变量,它们会让你的生活更轻松。如果没有 ?: never,它会告诉你对象中不存在名为 ... 的属性。

或者你可以只是使用对象而不是内联 props:

type Props = {
  heading: string
  description: string
  signUp?: {
    button1: string
    button2: string
    // ...
  }
  startFreeAccount?: {
    signUpButton: string
    // ...
  }
  // ...
}

我甚至会认为这些对象更容易阅读和使用。


<details>
<summary>英文:</summary>

You can do this with simple unions

```ts
type Props = {
  heading: string;
  description: string;
} &amp; (
  | {
      signUp?: false
      signUpButton1?: never
      // ...
    }
  | {
      signUp: true
      signUpButton1: string
      // ...
    }
) &amp; (
  | {
    startFreeAccount?: false;
    startFreeAccountSignUpButton?: never;
    // ...
  }
  | {
    startFreeAccount: true;
    startFreeAccountSignUpButton: string;
    // ...
  }
) &amp; (
  ...
)

Maybe add a utility type:

type OptionalProps&lt;K extends string, T&gt; = 
  | { [key in K]?: false } &amp; { [key in keyof T]?: never }
  | { [key in K]: true } &amp; T

type Props = {
  heading: string
  description: string
}
  &amp; OptionalProps&lt;&#39;signUp&#39;, {
    signUpButton1: string,
  }&gt;
  &amp; OptionalProps&lt;&#39;startFreeAccount&#39;, {
    startFreeAccountSignUpButton: string
  }&gt;
  &amp; ...

The properties with ?: never are not necessary, but they will make your life easier if you destructure props into individual variables. Without ?: never you won't be able to do it, it will tell that property with name ... doesn't exist in the object.

Or you can just use objects instead of inline props:

type Props = {
  heading: string
  description: string
  signUp?: {
    button1: string
    button2: string
    // ...
  }
  startFreeAccount?: {
    signUpButton: string
    // ...
  }
  // ...
}

I would even argue that these objects is easier to read and use

huangapple
  • 本文由 发表于 2023年2月19日 15:42:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/75498663.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定