为什么在枚举时类型没有重叠?

时间:2019-01-30 21:41:28

标签: reactjs typescript enums

我想弄清楚为什么TypeScript报告在这种情况下(playground link,由于Action.UP | Action.DOWNAction.LEFT之间没有类型重叠,我的条件将永远是假的:

class Component<S> {
    public state: S;
    public render() {}
}

enum Action {
    UP,
    DOWN,
    LEFT,
    RIGHT,
}

interface State {
    action: Action;
}

const initialAction: Action.UP | Action.DOWN = Action.UP;
class MyComponent extends Component<State> {
    public state = {
        action: initialAction,
    }

    public render() {
        // Why is action not of type Action as declared in the interface?
        const isLateral = this.state.action === Action.LEFT;
    }
}

如果this.state.action仅具有类型Action.UP | Action.DOWN的初始值,但在接口中被声明为类型Action,为什么不能将其与Action.LEFT进行比较?如果将来我可以将this.state.action重新分配为LEFTRIGHT,为什么条件始终为假?

3 个答案:

答案 0 :(得分:2)

回答“为什么?”

  

为什么动作不是接口中声明的动作类型?

它的类型不同,因为子类正在重新定义state属性,并为其提供比父类更窄的类型。如果您是设计使然,则可以通过在render()内进行强制转换来访问父类的更广泛的接口。

const isLateral = (this as Component<State>).state.action === Action.LEFT;

推荐方法

或者,执行React Component documentation所说的:

  

...如果您的组件需要使用本地状态,请直接在构造函数中将初始状态分配给this.state:

也就是说,不要重新定义父类的state属性;相反,请使用state为您提供的已经定义的extend属性。在构造函数中设置其初始值。

class MyComponent extends Component<State> {

    constructor() { 
        super();
        this.state = {
            action: initialAction,
        }
    }

    public render() {
        const isLateral = this.state.action === Action.LEFT;
    }
}

答案 1 :(得分:0)

您必须像这样输入公共状态:

public state: State = {
    action: initialAction,
}

否则Typescript会推断state.actioninitialAction的类型相同。

要回答您评论中的问题

playground link

在设置为新属性时,您在子类中重新定义了state的值和类型。

我的链接说明了这一点。我在父类count上添加了一个类型为number的新属性。如果我在子类中将其定义为新属性,则它将其推断为any,因此可以将其设置为render()中的字符串。

但是,您可以看到我如何处理原始的state属性。为了使用父级的状态类型,可以在构造函数中调用super(),然后定义this.state.action = initialAction;

这样,当您调用render()时,它将在Action上查找this.state.action类型,而不是新定义的Action.UP | Action.DOWN

答案 2 :(得分:0)

在我们的情况下,我们忘记了{},因为const A: React.FC<IProps> = (first, second, ...rest)必须是const A: React.FC<IProps> = ({first, second, ...rest})。这太糟糕了:)