如何使TypeScript接口道具依赖于同一接口中的另一个道具?

时间:2020-05-13 19:27:31

标签: reactjs typescript

type ButtonVariant = 'action' | 'hero';

type Size = 'small' | 'medium' | 'large';

export interface ButtonProps {
    variant: ButtonVariant;
    size?: Size;
}

export default function Button(props: ButtonProps): ReactElement {
    const { variant } = props;

    if (variant === 'hero')) {
        return <HeroButton {...props} />;
    }

    if (variant === 'pill') {
        return <PillButton {...props} />;
    }
}

在上面的代码中,我有两个React按钮的变体:HeroButtonPillButton

两个按钮都将“ ButtonProps”作为其道具类型。但是,我想让HeroButton仅 期望大小为“中”或“大”。 PillButton应接受“小”,“中”或“大”作为其大小尺寸。

问题:如何编写ButtonProps接口,以使Button组件允许(并在VS Code中建议)'small' | 'medium' | 'large'作为大小道具变体道具为“药丸”,但仅当变体道具为“英雄”时才允许'medium' | 'large'

注意:我已经研究了TypeScript区分联合来解决此问题,但尚未设法使它正常工作。

2 个答案:

答案 0 :(得分:1)

尝试一下:

export interface HeroButtonProps {
    variant: 'hero';
    size?: 'medium' | 'large';
}

export interface PillButtonProps {
    variant: 'pill';
    size?: 'small' | 'medium' | 'large';
}

export type ButtonProps = HeroButtonProps | PillButtonProps;

然后将HeroButton更改为仅接受HeroButtonProps,对于PillButton同样如此。

答案 1 :(得分:1)

类似的东西应该起作用

type DiscUnion =
| { variant: "hero"; size?: "medium" | "large" }
| { variant: "pill"; size?: "small" | "medium" | "large" };

export default function Button(props: DiscUnion): any {
    if (props.variant === "hero") {
        const w = props.size; //typeof w is "medium" | "large"
    }

    if (props.variant === "pill") {
        const w = props.size; //typeof w is "small" | "medium" | "large"
    }
}

// allowed
Button({ variant: "hero", size: "medium" });

// not allowed
Button({ variant: "hero", size: "small" });

请注意,我们不会破坏变体,否则您将失去控制流分析https://github.com/microsoft/TypeScript/issues/9998

编辑-这是一个游乐场链接https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wG4BYAKFEljgG9FiYBRAGyRCQDt4BfONlxwAREXQwRFSlRgBPMEjgARYAGc0AVW7AI3OAF4qAHwZwAbiijAUvAFyiAFkhxS4a4AC8kAfgciuABNgAFcQEThTETYrAHMkCL4qOBTIs0trWxh-MGA2NjcPbz9RNRAUfIiooNDwtOi4hLg+aSpMEO4MXX0ACRcIACEQmBg9AAowHDA1B1s5AEoHZAl2Th54emTUohgQqH0AHmDzAD5HYAOAemOTqiSZSnbOmG64AAU8tiGR8cmIadm3AWS2Yqy4vAYWxSOz2hxuACM5Egrjc7lQqEgAB60eCBJCYFAhNhYDpdPRwb6jbgTKYzFTqLQ6PSLJgrDjgjZQuBoPRqeCeQxwP7TAB0GRsvC5agA7sAYGhHHAaf81GKrBKYPNIZRUrruSg1EoRM5XA5Njq9Zaedw+XBpYLhaqikhSHBLpd5IoIJg7XB1KIamEqqIYlB4iIuZboUhdvs4Ac+jhKeT6CK046BJdbhbLfco-rDaJcpVtfnddbbfaDELaSLna73Z6kN7ff6RGUKgV6oG6lFQ+HI1GYXGDh98sn9Kn07TM9n83nUvd7ubdQcJxZ1VkDMb+hFnduexEs2jKCvUmvhlSN5leNuTRA914kNuOyXj5R7kA