如何为Typescript接口提供最多一个属性

8zzbczxx  于 2023-04-13  发布在  TypeScript
关注(0)|答案(2)|浏览(121)

具有以下React组件的接口:

export interface MyInterface  {
  name: string;
  isEasy?: boolean;
  isMedium?: boolean;
  isHard?: boolean;
}

它必须接受最后三个属性(isEasy、isMedium或isHard)中的最多一个属性
举个例子

<MyComponent name='John' /> // correct
<MyComponent name='John' isEasy /> // correct
<MyComponent name='John' isEasy isHard /> // incorrect

如何才能做到这一点?
试着像这样把他们结合起来,但没有成功:

interface MyInterface {
  name: string;
}

interface MyInterfaceEasy extends MyInterface {
  isEasy: true;
  isMedium?: never;
  isHard?: never;
}

interface MyInterfaceMedium extends MyInterface {
  isEasy: never;
  isMedium?: true;
  isHard?: never;
}

interface MyInterfaceHard extends MyInterface {
  isEasy: never;
  isMedium?: never;
  isHard?: true;
}

export type ExportedInterface =
  | MyInterfaceEasy
  | MyInterfaceMedium
  | MyInterfaceHard;

测试时使用:<MyComponent name='John' isEasy />
错误:

Types of property 'isEasy' are incompatible.
Type 'boolean' is not assignable to type 'undefined'
mi7gmzs6

mi7gmzs61#

一种方法是总是让其中一个困难是true,其余的是?: false。这样你就可以省略所有的props,或者只保留一个。设置两个困难会将两者都设置为true,因此它们不会被分配给ExportedInterface,Typescript会出错。
你可以在这里或在Typescript playground中看到一个例子:

interface MyInterface {
  name: string;
}

interface MyInterfaceEasy extends MyInterface {
  isEasy?: true;
  isMedium?: false;
  isHard?: false;
}

interface MyInterfaceMedium extends MyInterface {
  isEasy?: false;
  isMedium?: true;
  isHard?: false;
}

interface MyInterfaceHard extends MyInterface {
  isEasy?: false;
  isMedium?: false;
  isHard?: true;
}

export type ExportedInterface =
  | MyInterfaceEasy
  | MyInterfaceMedium
  | MyInterfaceHard;

declare const Component: FC<ExportedInterface>;

// OK
<Component name='none' />;
<Component name='easy' isEasy />;
<Component name='medium' isMedium />;
<Component name='hard' isHard />;
// Not OK
<Component name='mix' isEasy isHard />;

你也可以考虑采用一种不同的方法,你有一个 prop 是difficulty?: 'easy' | 'medium' | 'hard'。这将只允许一个难度。
你可以在这里或在TypescriptPlayground看到这种方法:

interface MyInterface {
  name: string;
  difficulty?: 'easy' | 'medium' | 'hard';
}
nfzehxib

nfzehxib2#

我想你可以把你的代码改成:

interface MyBaseInterface {
  name: string;
}

interface MyInterfaceEasy extends MyBaseInterface {
  isEasy?: boolean;
}

interface MyInterfaceMedium extends MyBaseInterface {
  isMedium?: boolean;
}

interface MyInterfaceHard extends MyBaseInterface {
  isHard?: boolean;
}

export type ExportedInterface =
  | MyInterfaceEasy
  | MyInterfaceMedium
  | MyInterfaceHard;

应该会有用的。

相关问题