2

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?

4
  • Why do you need either one? Why not using Component? These two are interfaces of the Component classes not instances. In most cases you create a component of your own by extending Component Commented May 25, 2016 at 16:44
  • but I don't create my own component. I only create definition for it. For example: declare module "react-whatever" { interface reactWhaterverProps{ id:number; name:string; }\n let reactWhaterver: __React.ComponentClass<reactWhateverProps>\n export default reactWhaterver; } so I don't need create some 'state' interface in this case, because it's not mine component and it's state is black box for me, is it correct? Commented May 25, 2016 at 17:06
  • Why not React.Component<ReachWhateverProps>? What exactly are you trying to do? Commented May 25, 2016 at 18:01
  • It's just not possible by typescript error because "Component" has 2 params <P,S>. I need only <P>. I create some definitions for react in DefinitelyTyped project. Here is one my example: github.com/DefinitelyTyped/DefinitelyTyped/blob/master/… Commented May 25, 2016 at 18:27

1 Answer 1

4

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" />
Sign up to request clarification or add additional context in comments.

2 Comments

I think I got it, so if I want create definition for component I should think about component as about function that takes interface as constructor for react component and return new instance of it? So result will be: declare module "some-react-component" { interface SomeReactComponent { id:number; name:any; } let SomeReactComponent:new() => React.Component<SomeReactComponent,{}> export default SomeReactComponent; } is it correct?
Check my revised answer, hopefully it will make things clearer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.