在 Typescript 中扩展 React 抽象组件
Extend React Abstract Component in Typescript
我正在用 React 中的演示文稿创建一个库。每个演示组件必须至少设置一些属性,因此我创建了一个可以扩展以创建演示文稿的打字稿文件:
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<{}>'
我已经花了几个小时搜索如何正确使用此处的类型,但我一头雾水。谁能给我指出正确的方向?
编辑:
为了进一步说明,我正在使用这些静态变量在我的索引页面上加载演示文稿列表。我有一个 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/function。所以使用接口,看这个例子:
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>;
}
}
我正在用 React 中的演示文稿创建一个库。每个演示组件必须至少设置一些属性,因此我创建了一个可以扩展以创建演示文稿的打字稿文件:
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<{}>'
我已经花了几个小时搜索如何正确使用此处的类型,但我一头雾水。谁能给我指出正确的方向?
编辑:
为了进一步说明,我正在使用这些静态变量在我的索引页面上加载演示文稿列表。我有一个 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/function。所以使用接口,看这个例子:
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>;
}
}