Writing a higher order reactive component using TypeScript

I am writing a high-order React component (HOC) with TypeScript. HOC should take one more pillar than a wrapped component, so I wrote this:

type HocProps {
    // Contains the prop my HOC needs
    thingy: number
}
type Component<P> = React.ComponentClass<P> | React.StatelessComponent<P>
interface ComponentDecorator<TChildProps> {
    (component: Component<TChildProps>): Component<HocProps & TChildProps>;
}
const hoc = function<TChildProps>(): (component: Component<TChildProps>) => Component<HocProps & TChildProps) {
    return (Child: Component<TChildProps>) => {
        class MyHOC extends React.Component<HocProps & TChildProps, void> {
            // Implementation skipped for brevity
        }
        return MyHOC;
    }
}
export default hoc;

, hoc - , HOC. HOC ( ) , Component. , , TChildProps . Component. TChildProps ( , TChildProps) , ( HocProps). ( HocProps Component).

, HOC, :

// outside parent component
const WrappedChildComponent = hoc()(ChildComponent);

// inside parent component
render() {
    return <WrappedChild
                thingy={ 42 } 
                // Prop 'foo' required by ChildComponent
                foo={ 'bar' } />
}

TypeScript:

TS2339: Property 'foo' does not exist on type 'IntrinsicAttributes & HocProps & {} & { children? ReactNode; }'

, TypeScript TChildProps , ChildComponent. TypeScript ?

+8
3

: hoc :

import ChildComponent, { Props as ChildComponentProps } from './child';
const WrappedChildComponent = hoc<ChildComponentProps>()(ChildComponent);

. , ( ), , TypeScript , .

0

, , HOC, , "thingy", , , "thingy", , .

, - :

render() {
    return (
        <WrappedComponent thingy={this.props.thingy} {...this.props}/>
    );
}

, WrappedComponent thingy . , . , , . .

, , HOC , prop thingy - .

interface HocProps {
    // Contains the prop my HOC needs
    thingy: number;
}

const hoc = function<P extends HocProps>(
    WrappedComponent: new () => React.Component<P, any>
) {
    return class MyHOC extends React.Component<P, any> {
        render() {
            return (
                <WrappedComponent {...this.props}/>
            );
        }
    }
}
export default hoc;

// Example child class

// Need to make sure the Child class includes 'thingy' in its props definition or
// this will throw an error below where we assign `const Child = hoc(ChildClass)`
interface ChildClassProps {
    thingy: number;
}

class ChildClass extends React.Component<ChildClassProps, void> {
    render() {
        return (
            <h1>{this.props.thingy}</h1>
        );
    }
}

const Child = hoc(ChildClass);

, , HOC . HOC - , . , , , , . HOC .

:

interface ChildComponentProps {
    lastUpdated: number;
    data: any;
}

class ChildComponent extends React.Component<ChildComponentProps, void> {
    render() {
        return (
            <div>
                <h1>{this.props.lastUpdated}</h1>
                <p>{JSON.stringify(this.props.data)}</p>
            </div>
        );
    }
}

HOC, setInterval, :

interface AutoUpdateProps {
    lastUpdated: number;
}

export function AutoUpdate<P extends AutoUpdateProps>(
    WrappedComponent: new () => React.Component<P, any>,
    updateInterval: number
) {
    return class extends React.Component<P, any> {
        autoUpdateIntervalId: number;
        lastUpdated: number;

        componentWillMount() {
            this.lastUpdated = 0;
            this.autoUpdateIntervalId = setInterval(() => {
                this.lastUpdated = performance.now();
                this.forceUpdate();
            }, updateInterval);
        }

        componentWillUnMount() {
            clearInterval(this.autoUpdateIntervalId);
        }

        render() {
            return (
                <WrappedComponent lastUpdated={this.lastUpdated} {...this.props}/>
            );
        }
    }
}

, :

const Child = AutoUpdate(ChildComponent, 1000);
+6

, hoc , - , - . hoc . hoc()(Foo), Typescript hoc() - . , hoc<FooProps>()(Foo).

hoc , hoc , ( ).

const hoc = function<TChildProps>(): (component: Component<TChildProps>) => Component<HocProps & TChildProps) {
    return (Child: Component<TChildProps>) => {

const hoc = function(): <TChildProps>(component: Component<TChildProps>) => Component<HocProps & TChildProps) {
    return <TChildProps>(Child: Component<TChildProps>) => {

( <TChildProps>)

, hoc(), , hoc()(Foo), hoc()<FooProps>(Foo).

, hoc - - , " , , ", . , , hoc, .

, - hoc, . , , . - hoc, , , , . , hoc , () hoc()) , - ,

0
source

Source: https://habr.com/ru/post/1675909/


All Articles