如果我在 React (Typescript) 中从 Parent 扩展 Child class,为什么 state 在 Parent class 中是只读的?
Why is state readonly in Parent class if I extend a Child class from Parent in React (Typescript)?
我已经为 Parent class 创建了一个接口,为 State 定义:
interface ParentState { name: string; }
我创建了一个具有上述类型状态的组件:
class Test extends React.Component<{}, ParentState> {
constructor(props: any) {
super(props);
// Works fine!
this.state = { name: '' };
}
}
这是按预期工作的。但是,如果我创建一个父组件和一个子组件,其中子组件继承自父状态,子状态继承自父状态,则父状态变为只读。
interface ChildState extends ParentState {}
class Parent<P, S extends ParentState> extends React.Component<P, S> {
constructor(props: P) {
super(props);
this.state = { name: '' };
^^^^^^^^^^
// Compilation error!
// TS2322: Type '{}' is not assignable to type 'Readonly<S>'.
}
render() {
return <div>parent</div>;
}
}
class Child extends Parent<{}, ChildState> {
constructor(props: ChildProps) {
super(props);
// Works fine!
this.state = { name: '' };
}
render() {
return <div>child</div>;
}
}
谁能解释一下这种行为。
P.S。
我还有几个问题。
此外,在 React 库中,当我打开 index.d.ts 文件时,state 实际上是 readonly.这在前面提到的 class 测试中是如何工作的?
如果我在测试 class 的构造函数中没有提及 props 的类型,则会出现编译错误
TS7006: Parameter 'props' implicitly has an 'any' type.
为什么不采用 class 定义中提到的类型 {}
?
您得到的错误类似于:
Type '{ name: string }' is not assignable to type 'Readonly<S>'.
这告诉你,如果你有一个 Readonly<S>
类型的变量,那么给它赋一个 { name: string }
类型的值是不安全的。让我们看看为什么。
由于 S
是通用的,因此您使用它编写的代码需要与替换 S
的任何有效具体类型兼容。 S
上的约束是 S extends ParentState
,所以让我们想出一个满足该约束的类型并用它实例化 Parent
:
interface ProblemChildState extends ParentState {
naughtiness: true
}
const problemComponent = new Parent<{}, ProblemChildState>({});
让我们想象一下构造函数在做什么,现在 S
已经具体指定为 ProblemChildState
:
this.state = { name: '' }; // oops!
this.state
的类型是 Readonly<ProblemChildState>
,但如您所见,值 { name: '' }
根本不是有效的 ProblemChildState
,因为它缺少 naughtiness
属性.
由于该赋值对于具体 ProblemChildState
无效,因此该赋值对于泛型 S
必定无效。因此错误。
在实践中,很难将文字值分配给泛型类型的变量。即使在极少数情况下,您可以想出适用于泛型类型参数的所有可能实例的东西,编译器也可能会给您一个错误,因为这种情况太少了,它无法检查,您需要做一个 type assertion。事实上,您可以通过这样的断言来解决这个问题:
this.state = { name: '' } as Readonly<S>; // not safe!
但由于上述原因,这样做并不安全。理想情况下,您会更改代码以不需要设置 state
,直到您拥有 S
的具体类型。可能通过使 Parent
成为 abstract
class?
无论如何,希望对您有所帮助。祝你好运!
我已经为 Parent class 创建了一个接口,为 State 定义:
interface ParentState { name: string; }
我创建了一个具有上述类型状态的组件:
class Test extends React.Component<{}, ParentState> {
constructor(props: any) {
super(props);
// Works fine!
this.state = { name: '' };
}
}
这是按预期工作的。但是,如果我创建一个父组件和一个子组件,其中子组件继承自父状态,子状态继承自父状态,则父状态变为只读。
interface ChildState extends ParentState {}
class Parent<P, S extends ParentState> extends React.Component<P, S> {
constructor(props: P) {
super(props);
this.state = { name: '' };
^^^^^^^^^^
// Compilation error!
// TS2322: Type '{}' is not assignable to type 'Readonly<S>'.
}
render() {
return <div>parent</div>;
}
}
class Child extends Parent<{}, ChildState> {
constructor(props: ChildProps) {
super(props);
// Works fine!
this.state = { name: '' };
}
render() {
return <div>child</div>;
}
}
谁能解释一下这种行为。
P.S。
我还有几个问题。
此外,在 React 库中,当我打开 index.d.ts 文件时,state 实际上是 readonly.这在前面提到的 class 测试中是如何工作的?
如果我在测试 class 的构造函数中没有提及 props 的类型,则会出现编译错误
TS7006: Parameter 'props' implicitly has an 'any' type.
为什么不采用 class 定义中提到的类型
{}
?
您得到的错误类似于:
Type '{ name: string }' is not assignable to type 'Readonly<S>'.
这告诉你,如果你有一个 Readonly<S>
类型的变量,那么给它赋一个 { name: string }
类型的值是不安全的。让我们看看为什么。
由于 S
是通用的,因此您使用它编写的代码需要与替换 S
的任何有效具体类型兼容。 S
上的约束是 S extends ParentState
,所以让我们想出一个满足该约束的类型并用它实例化 Parent
:
interface ProblemChildState extends ParentState {
naughtiness: true
}
const problemComponent = new Parent<{}, ProblemChildState>({});
让我们想象一下构造函数在做什么,现在 S
已经具体指定为 ProblemChildState
:
this.state = { name: '' }; // oops!
this.state
的类型是 Readonly<ProblemChildState>
,但如您所见,值 { name: '' }
根本不是有效的 ProblemChildState
,因为它缺少 naughtiness
属性.
由于该赋值对于具体 ProblemChildState
无效,因此该赋值对于泛型 S
必定无效。因此错误。
在实践中,很难将文字值分配给泛型类型的变量。即使在极少数情况下,您可以想出适用于泛型类型参数的所有可能实例的东西,编译器也可能会给您一个错误,因为这种情况太少了,它无法检查,您需要做一个 type assertion。事实上,您可以通过这样的断言来解决这个问题:
this.state = { name: '' } as Readonly<S>; // not safe!
但由于上述原因,这样做并不安全。理想情况下,您会更改代码以不需要设置 state
,直到您拥有 S
的具体类型。可能通过使 Parent
成为 abstract
class?
无论如何,希望对您有所帮助。祝你好运!