如何编写可扩展Props与State的React抽象组件类?
解决React TypeScript抽象类继承的State类型不兼容问题
你遇到的TS2322错误核心原因在于泛型S的约束与state赋值的类型不匹配:
你的Animal类定义了泛型S extends AnimalState,意味着S可以是AnimalState的任意扩展类型(比如子类Cat的CatState就多了shouldSeekWarmth属性)。但你在基类构造函数里直接给this.state赋值了一个仅满足AnimalState的对象,TypeScript无法确定这个对象能覆盖S的所有属性要求,所以抛出了类型不兼容的错误。
另外你的Cat类构造函数还有两个小问题:
- 构造函数的
props类型错误地写成了P,应该是CatProps(因为Cat已经指定了Animal的泛型参数为CatProps和CatState) state里的willHibernate是笔误,应该是shouldHibernate(对应AnimalState的属性)
下面是修正后的完整代码:
1. 修正抽象基类Animal
我们可以通过类型断言告诉TypeScript,我们赋值的state对象符合Readonly<S>的要求(因为S extends AnimalState,所以必然包含shouldHibernate属性,这个断言是安全的):
import * as React from "react"; export interface AnimalProps { isHibernatory: boolean; } export interface AnimalState { shouldHibernate: boolean; } export abstract class Animal<P extends AnimalProps, S extends AnimalState> extends React.Component<P, S> { constructor(props: P) { super(props); // 使用类型断言确保TypeScript认可这个state赋值符合S的要求 this.state = { shouldHibernate: props.isHibernatory } as Readonly<S>; } }
2. 修正子类Cat
修正构造函数的props类型,并正确初始化state的所有属性:
import * as React from "react"; import { AnimalProps, AnimalState, Animal } from "./Animal"; export interface CatProps extends AnimalProps { isHairless: boolean; } export interface CatState extends AnimalState { shouldSeekWarmth: boolean; } export class Cat extends Animal<CatProps, CatState> { constructor(props: CatProps) { super(props); // 初始化所有CatState的属性:继承的shouldHibernate + 自定义的shouldSeekWarmth this.state = { shouldHibernate: props.isHibernatory, shouldSeekWarmth: props.isHairless }; } }
额外优化建议
如果你想避免类型断言,也可以调整基类的泛型设计,让基类只负责自身的state属性,子类通过super()初始化基类state后,再补充自己的state属性:
// Animal类调整 export abstract class Animal<P extends AnimalProps, S extends AnimalState> extends React.Component<P, S> { constructor(props: P) { super(props); // 这里只初始化AnimalState的部分,子类后续补充S的其他属性 (this.state as AnimalState).shouldHibernate = props.isHibernatory; } } // Cat类调整 export class Cat extends Animal<CatProps, CatState> { constructor(props: CatProps) { super(props); this.state.shouldSeekWarmth = props.isHairless; } }
不过第一种使用类型断言的方式更简洁,也符合React类组件的常规写法。
内容的提问来源于stack exchange,提问作者Jamie Birch
相关产品推荐
相关产品推荐

