繁体   English   中英

在 Typescript 中扩展 React 抽象组件

[英]Extend React Abstract Component in Typescript

我正在创建一个带有 React 演示文稿的库。 每个演示文稿组件必须至少设置一些属性,因此我创建了一个 typescript 文件,可以扩展该文件以创建演示文稿:

import React from "react";

abstract class _Presentation<P,S> extends React.Component{
    static title: string
    static description: string
    static date: Date
    static uri: string
}

export type PresentationType = typeof _Presentation

export function Presentation<P,S>(mandatory: {
    title: string
    description: string
    date: Date
    uri: string
}) {
    return class extends _Presentation<P, S> {
        static title = mandatory.title
        static description = mandatory.description
        static date = mandatory.date
        static uri = mandatory.uri
    }
}

当我尝试实现一个演示时,一切都很顺利,我可以像这样创建一个组件:

import React from 'react';

class SomePresentation extends Presentation({
    title: "My presentation's title",
    description: "My presentation's description",
    date: new Date(2021, 1, 22, 15, 30, 0),
    uri: "/presentation-slug"
}) {

    render = () => (
        <div>
          Test
        </div>
    );
}

export default SomePresentation;

当我开始使用状态时,一切都开始分崩离析。 我的摘要的组件类型似乎有问题。 我不知道如何正确地使用正确的类型。

import React from 'react';

class SomePresentation extends Presentation<{}, {
    width: number,
    height: number
}>({
    title: "My presentation's title",
    description: "My presentation's description",
    date: new Date(2021, 1, 22, 15, 30, 0),
    uri: "/presentation-slug"
}) {

    constructor(props: any) {
        super(props);
        this.state = {width: 0, height: 0}
        this.updateWindowDimensions = this.updateWindowDimensions.bind(this);
    }

    componentDidMount() {
        this.updateWindowDimensions();
        window.addEventListener('resize', this.updateWindowDimensions);
    }

    componentWillUnmount() {
        window.removeEventListener('resize', this.updateWindowDimensions);
    }

    updateWindowDimensions() {
        this.setState({width: window.innerWidth, height: window.innerHeight});
    }

    render = () => (
        <div style={{width: this.state.width, height:this.state.height}}>
           
        </div>
    );
}

export default SomePresentation;

我在哪里使用this.state.width我收到以下错误:

Property 'width' does not exist on type 'Readonly<{}>'

我已经花了几个小时搜索如何正确使用这里的类型,但我迷失了。 谁能指出我正确的方向?


编辑:为了进一步澄清,我正在使用这些 static 变量在我的索引页面上加载演示文稿列表。 我有一个导出所有演示组件的index.tsx 然后在主页上我有以下代码:

import * as presentations from './presentations/index'
...
const presentationClasses = Object.values(presentations);
...

{presentationClasses.map((presentation, index) =>
    <Route key={presentation.uri} path={presentation.uri}>
        {React.createElement(presentation)}
    </Route>
)}

TypeScript 使用编译器,当编译器生成 JavaScript 时,所有抽象属性都被删除。 所有类型的别名和接口。 因此,当您有一个具有所有抽象属性的抽象 class 时,它会变慢,TS 会生成空类/函数。 所以使用接口,看这个例子:

class A {
    inherited = 1;
}
interface B {
    abstract: string;
}
class C extends A implements B {
    abstract = "Yes, I implement"
}

好多了,编译结果:

"use strict";
class A {
    constructor() {
        this.inherited = 1;
    }
}
class C extends A {
    constructor() {
        super(...arguments);
        this.abstract = "Yes, I implement";
    }
}

所以没有空的 class。 我完全推荐这个:

interface _PresentatonBase {
    title: string;
    description: string;
    date: Date;
    uri: string;
}

interface _Presentation<P, S> extends React.ComponentClass<P, S>, _PresentatonBase {}

function Presentation<S, P = {}>(mandatory: _PresentatonBase, state: S): _Presentation<P, S> {
    return class SyntheticPresentation extends React.Component<P, S> {
        state = state;
        static title = mandatory.title;
        static description = mandatory.description;
        static date = mandatory.date;
        static uri = mandatory.uri;
    };
}

class SomePresentation extends Presentation({
    date: new Date(),
    description: "",
    title: "",
    uri: ""
}, {
    width: 0,
    height: 0
}) {
    constructor(props: any) {
        super(props);
        this.updateWindowDimensions = this.updateWindowDimensions.bind(this);
    }

    componentDidMount() {
        this.updateWindowDimensions();
        window.addEventListener('resize', this.updateWindowDimensions);
    }

    componentWillUnmount() {
        window.removeEventListener('resize', this.updateWindowDimensions);
    }

    updateWindowDimensions() {
        this.setState({width: window.innerWidth, height: window.innerHeight});
    }

    render() {
        return <div style={{width: this.state.width, height: this.state.height}}>

        </div>;
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM