根据通用接口的另一个属性来设置一个必需的属性

时间:2020-04-14 20:14:47

标签: reactjs typescript

我有一个React组件的接口。那里有一堆属性,但是我希望一个属性影响其他属性。 所以,我有:

export interface IMyAwesomeComponentProps<T = {}> {
    className: string
    defaultPath?: ISomeOtherInterface<T>

    // more properties...
    // ...and finally

    isDraggable?: boolean
    onDrag?: () => {}
}

这个东西是这样实现的:

export class MyAwesomeComponent<T> extends React.Component<IMyAwesomeComponentProps<T>> {
   //...
}

所以,我要做的是,当我将“ isDraggable”传递为“ true”时,我希望必需

要解决此问题,我首先从界面中排除了“ onDrag”功能,并添加了新类型。然后,我创建了一个实用程序类型,该实用程序类型基本上说:“如果“ isDraggable”是正确的,则返回结合了“ TDraggableProps”的接口,否则将接口还给我。 总体看起来像这样:

type TDraggableProps = {  
  onDrag: () => void
  // maybe some more props  
}

type Test<I extends ITreeProps> = I['isDraggable'] extends true ? I & TDraggableProps : I

export class MyAwesomeComponent<T> extends React.Component<Test<IMyAwesomeComponentProps<T>>>

Aaaand,这种方法行之有效,但事实并非如此。而且我不知道该如何处理接口中的泛型。

3 个答案:

答案 0 :(得分:1)

我将通过创建IDraggable接口来更改您的接口IMyAwesomeComponentProps签名,并将其包含在您的IMyAwesomeComponentProps中。当然,这里假设isDraggable = falseonDrag is defined的情况是没有用的...

类似这样的东西:

    interface ITest<T = {}> {
    a: string;
    b: IInner<T>;
    isDraggable?: IIsDragble;
}

interface IIsDragble {
    onDrag: () => void;
}

const a: ITest = {
    a: "dsd",
    b: {
        valInner: "ssdds",
    },
};

const b: ITest = {
    a: "dsd",
    b: {
        valInner: "ssdds",
    },
    isDraggable: {
        onDrag: () => true,
    },
};

答案 1 :(得分:1)

您可以使用Discriminated union

type Props = {
  isDraggable: true;
  onDrag: () => void;
} | {
  isDraggable: false;
}

const Component = (props: Props) => {}

Component({ isDraggable: false }); // Ok
Component({ isDraggable: true }); // Error onDrag is missing
Component({ isDraggable: true, onDrag: () => {} }); // Ok

如果您需要添加一些常见的道具,则可以将这些类型作为接口并扩展一些基本接口,也可以将它们提取为单独的类型并加入道具

type Props = {
  isDraggable: true;
  onDrag: () => void;
} | {
  isDraggable: false;
}

type StaticProps = {
  className: string;
}

const Component = (props: Props & StaticProps) => {}

Component({ isDraggable: false, className: "123" });
Component({ isDraggable: true, className: "123" }); // Error onDrag is missing
Component({ isDraggable: true, onDrag: () => {}, className: "123" }); // Ok

答案 2 :(得分:1)

我将Props设置为类型,然后将所有通用属性和不同属性的所有界面移开,我认为这种方法看起来干净易懂:

interface Common {
  x: number;
  y: number;
  z: number;
}

interface RequiredB {
  a: true;
  b: () => {}
}

interface OptionalB {
  a: false;
  b?: () => {}
}

type Props = Common & (RequiredB | OptionalB);

const obj: Props = {
  x: 1,
  y: 2,
  z: 3,
  //a: false, // b is not required now
  //a: true, // b is required now
}