如何从继承的 class 覆盖 React.Component 状态类型?
How to overwrite React.Component state type from inherited class?
我有一个组件 class 扩展了另一个组件,我想弄清楚如何覆盖我从中继承的状态类型。
这是一个例子:
class MyComponent extends React.Component<SomeProps, SomeState> {
// ...
}
class ExtendedComponent extends MyComponent {
// How to overwrite SomeState?
// This component needs to store a different model of state.
}
我需要 ExtendedComponent
为其 state
使用不同的 interface
,但我不太清楚如何完成此操作。
编辑:现在就去某个地方!
但是,现在 Parent
充斥着与状态修改有关的各种错误。到目前为止,这是我得到的:
interface ParentProps {
a: string;
}
interface ParentState {
b: string;
}
class Parent<P, S> extends React.Component<ParentProps & P, ParentState & S> {
constructor(props) {
super(props);
// Type '{ b: "hello"; }' is not assignable to type 'Readonly<ParentState & S>'
this.state = {
b: 'hello',
};
}
aFunction(): void {
/*
Argument of type '{ b: "testing"; }' is not assignable to parameter of type '(ParentState & S) | ((prevState: Readonly<ParentState & S>, props: Readonly<ParentProps & P>) => (ParentState & S) | Pick<ParentState & S, "b">) | Pick<ParentState & S, "b">'.
Type '{ b: "testing"; }' is not assignable to type 'Pick<ParentState & S, "b">'.
Types of property 'b' are incompatible.
Type '"testing"' is not assignable to type 'string & S["b"]'.
Type '"testing"' is not assignable to type 'S["b"]'.
*/
this.setState({
b: 'testing',
});
}
}
interface ChildProps {
c: string;
}
interface ChildState {
d: string;
}
class Child extends Parent<ChildProps, ChildState> {
constructor(props) {
super(props);
// This is what I'm after -- and TypeScript doesn't complain :)
this.state = {
b: 'hello',
d: 'world',
};
}
}
编辑 2:
回想起来,将近两年后:
由 React 的维护者扩展另一个组件 class is not recommended。这是有充分理由的,因为我必须在糟糕的生产应用程序中维护这种方法!我最终使用高阶组件和自定义挂钩重写了大量代码。
此用例得不到很好的支持是有原因的,请避免因过度设计组件而导致复杂化!想象一下,试图向另一位开发人员解释您那一团糟的继承问题。
仅仅因为它听起来很酷而且您可以做到,并不意味着您应该这样做。我强烈建议使用功能组件,如果您需要共享功能,请使用 higher-order functions, and/or custom hooks.
我猜你不想替换 props 和状态,因为你可能需要一个通用接口来让父 class 工作。所以你可以让你的父 class 通用,然后合并 props/state 的附加部分。
class MyComponent<P, S> extends React.Component<ParentProps & P, ParentState & S> {}
// ^ Generic P is for child props, Generic S is for child state
使用示例:
type ParentProps = { a: number }
type ParentState = { b: number }
class MyComponent<P, S> extends React.Component<ParentProps & P, ParentState & S> {}
let parentComponent = <MyComponent a={1} />
type ChildProps = { c: number }
type ChildState = { d: number }
class ExtendedComponent extends MyComponent<ChildProps, ChildState> {}
let childComponent = <ExtendedComponent a={1} c={2} />
对于搜索此内容并陷入“EDIT 2”问题的任何人,一种解决方法是像这样在您的 setState() 调用中传播以前的状态。
this.setState(prevState => { return { ...prevState, foo: newFoo }});
这是必需的,这样无论 S 模板中有什么,它都会传播并且不会被覆盖(并且您还可以使扩展组件通用并从中继承等等)。
你也是,如果你想在构造函数中设置状态,你可以这样做
super(props);
this.state = {
...this.state,
foo: newFoo
};
这样,在父 class 中初始化的状态将保持不变。如果您知道父级状态的每个字段,您也可以覆盖它。
我有一个组件 class 扩展了另一个组件,我想弄清楚如何覆盖我从中继承的状态类型。
这是一个例子:
class MyComponent extends React.Component<SomeProps, SomeState> {
// ...
}
class ExtendedComponent extends MyComponent {
// How to overwrite SomeState?
// This component needs to store a different model of state.
}
我需要 ExtendedComponent
为其 state
使用不同的 interface
,但我不太清楚如何完成此操作。
编辑:现在就去某个地方!
但是,现在 Parent
充斥着与状态修改有关的各种错误。到目前为止,这是我得到的:
interface ParentProps {
a: string;
}
interface ParentState {
b: string;
}
class Parent<P, S> extends React.Component<ParentProps & P, ParentState & S> {
constructor(props) {
super(props);
// Type '{ b: "hello"; }' is not assignable to type 'Readonly<ParentState & S>'
this.state = {
b: 'hello',
};
}
aFunction(): void {
/*
Argument of type '{ b: "testing"; }' is not assignable to parameter of type '(ParentState & S) | ((prevState: Readonly<ParentState & S>, props: Readonly<ParentProps & P>) => (ParentState & S) | Pick<ParentState & S, "b">) | Pick<ParentState & S, "b">'.
Type '{ b: "testing"; }' is not assignable to type 'Pick<ParentState & S, "b">'.
Types of property 'b' are incompatible.
Type '"testing"' is not assignable to type 'string & S["b"]'.
Type '"testing"' is not assignable to type 'S["b"]'.
*/
this.setState({
b: 'testing',
});
}
}
interface ChildProps {
c: string;
}
interface ChildState {
d: string;
}
class Child extends Parent<ChildProps, ChildState> {
constructor(props) {
super(props);
// This is what I'm after -- and TypeScript doesn't complain :)
this.state = {
b: 'hello',
d: 'world',
};
}
}
编辑 2:
回想起来,将近两年后:
由 React 的维护者扩展另一个组件 class is not recommended。这是有充分理由的,因为我必须在糟糕的生产应用程序中维护这种方法!我最终使用高阶组件和自定义挂钩重写了大量代码。
此用例得不到很好的支持是有原因的,请避免因过度设计组件而导致复杂化!想象一下,试图向另一位开发人员解释您那一团糟的继承问题。
仅仅因为它听起来很酷而且您可以做到,并不意味着您应该这样做。我强烈建议使用功能组件,如果您需要共享功能,请使用 higher-order functions, and/or custom hooks.
我猜你不想替换 props 和状态,因为你可能需要一个通用接口来让父 class 工作。所以你可以让你的父 class 通用,然后合并 props/state 的附加部分。
class MyComponent<P, S> extends React.Component<ParentProps & P, ParentState & S> {}
// ^ Generic P is for child props, Generic S is for child state
使用示例:
type ParentProps = { a: number }
type ParentState = { b: number }
class MyComponent<P, S> extends React.Component<ParentProps & P, ParentState & S> {}
let parentComponent = <MyComponent a={1} />
type ChildProps = { c: number }
type ChildState = { d: number }
class ExtendedComponent extends MyComponent<ChildProps, ChildState> {}
let childComponent = <ExtendedComponent a={1} c={2} />
对于搜索此内容并陷入“EDIT 2”问题的任何人,一种解决方法是像这样在您的 setState() 调用中传播以前的状态。
this.setState(prevState => { return { ...prevState, foo: newFoo }});
这是必需的,这样无论 S 模板中有什么,它都会传播并且不会被覆盖(并且您还可以使扩展组件通用并从中继承等等)。
你也是,如果你想在构造函数中设置状态,你可以这样做
super(props);
this.state = {
...this.state,
foo: newFoo
};
这样,在父 class 中初始化的状态将保持不变。如果您知道父级状态的每个字段,您也可以覆盖它。