Rajab Shakirov Rajab Shakirov - 6 months ago 91
Javascript Question

difference between ClassicComponentClass and ComponentClass in reactJS

I create my typescript definitions for some

reactJS
components and I see that in react.d.ts file there is 2 interfaces:

interface ComponentClass<P> {
new(props?: P, context?: any): Component<P, ComponentState>;
propTypes?: ValidationMap<P>;
contextTypes?: ValidationMap<any>;
childContextTypes?: ValidationMap<any>;
defaultProps?: P;
displayName?: string;
}


and:

interface ClassicComponentClass<P> extends ComponentClass<P> {
new(props?: P, context?: any): ClassicComponent<P, ComponentState>;
getDefaultProps?(): P;
}


I see that ClassicComponentClass extends ComponentClass, but when I should use one of these? (when creating definition for component) Does this depends on how the component was created?

Answer

I think you are missing what ComponentClass is.

Here's a short example:

interface MyClassClass {
    new (): MyClass;
}

class MyClass {}

let ctor: MyClassClass = MyClass;
let instance: MyClass = new ctor();

In this example MyClass is like React.Component and MyClassClass is React.ComponentClass.

The actual instances in your case are the components and not the component class, and you should use that.
If you don't want to specify a state then you can simply do:

React.Component<ReachWhateverProps, {}>

Edit

First, in the future if your comment includes code (that spans across a few lines) then just edit your question and add the code and asking the follow up questions, and just add a comment saying that you've edited your question, that will make it much easier to understand the code.

As for the difference between the class vs instance, I think that the best example is the javascript Array.
If you look at the definition (in lib.d.ts) you'll see (depending on whether it's ES5 or ES6):

interface Array<T> {
    // array instance methods
}

interface ArrayConstructor {
    new (arrayLength?: number): any[];
    new <T>(arrayLength: number): T[];
    new <T>(...items: T[]): T[];
    (arrayLength?: number): any[];
    <T>(arrayLength: number): T[];
    <T>(...items: T[]): T[];
    isArray(arg: any): arg is Array<any>;
    prototype: Array<any>;
}

declare var Array: ArrayConstructor;

(from the ES5 lib.d.ts)

As you can see all of the instance member/methods (such as length, push etc) are in the Array<T> interface, the ctor functions and static class functions (such as Array.isArray) are in the ArrayConstructor definition.

In javascript class ctors are just functions that are called using the new keyword, so this:

class A {
    x: number;

    constructor(x: number) {
        this.x = x;
    }
}

compiles into:

var A = (function () {
    function A(x) {
        this.x = x;
    }
    return A;
}());

So A is basically just a function, and in order to create an instance you simply:

let a: A = new A(5);

So the ctor interface is: { new (x: number): A }, or:

interface AConstructor {
    new (x: number): A;
}

As for react, it is recommended to have instance data in the props or state and not as class members.
The reason for this is that the Component lifecycle is only aware of those and react to changes in them.
So I'd do something like:

interface MyComponentProperties {
    id: string; 
    name: string;
}

class MyComponent extends React.Component<MyComponentProperties, {}> {
    render() {
        return <div className={ this.props.id }>{ this.props.name }</div>;
    }
}

let myComponent = <MyComponent id="mc4" name="my component 4" />