我想弄清楚为什么TypeScript报告在这种情况下(playground link,由于Action.UP | Action.DOWN
和Action.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
重新分配为LEFT
或RIGHT
,为什么条件始终为假?
答案 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.action
与initialAction
的类型相同。
在设置为新属性时,您在子类中重新定义了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})
。这太糟糕了:)