Search code examples
reactjseventstypescriptdefinitelytyped

How to expose a 'generic' event from a custom React component in TypeScript v2.x


When we were still using Typescript 1.8.x in combination with the (Definitely Typed) type description files of React of that time, we used the 'Event' type to declare a 'generic' event in React component properties. We then could attach the value of that property (being and event handler function) to for example the 'onChange' property of an HtmlInputElement.

interface IIcoonProps {
    onClick?: Event;
}

interface IIcoonDetails {
    cssClass: string;
    standaardTooltip: string;
}

class Icoon extends React.Component<IIcoonProps, {}> {



public render(): JSX.Element {

    return (<span   className={klassenamen}
                    title={nieuweTooltip}
                    onClick={this.props.onClick} />);
    }
}

We recently updated to TypeScript 2.2.2 and also updated the type definitions that we're using. Now we can't use the generic 'Event' type anymore, because it will result in an exception like "Type 'Event' is not assignable to type 'EventHandler>'".

Of course when I change the type of the property in the properties interface of the custom component into 'React.MouseEvent', the problem is solved. But..... I don't want to have the parent component of this component to be aware of the underlying type (in this example HtmlInputElement), because it is an event that is mentioned in the properties of my own component. I only need to pass the event to the parent component, because I would like the parent component to be able to use the methods like 'PreventDefault' of the event. I am using different properties and methods within my IComponentProps interface to publish for example changed values of a text input.

The code below is working, but not desirable.

interface IIcoonProps {
    onClick?: React.EventHandler<React.MouseEvent<HTMLSpanElement>>;
}

interface IIcoonDetails {
    cssClass: string;
    standaardTooltip: string;
}

class Icoon extends React.Component<IIcoonProps, {}> {

public render(): JSX.Element {

    return (<span   className={klassenamen}
                    title={nieuweTooltip}
                    onClick={this.props.onClick} />);
    }
}

Does anybody know how, when using TypeScript and React one can use an generic type for an event like we did before when using the 'Event' type, without using generics (like MouseEvent).

Update: added code example


Solution

  • Your code seems fine to me, but if you don't want to be specific about the type of the target element then you can use HTMLElement:

    interface IIcoonProps {
        onClick?: React.EventHandler<React.MouseEvent<HTMLElement>>;
    }
    

    That will work with future possible changes (let's say from HTMLSpanElement to HTMLDivElement).

    Also, you can use this signature instead:

    interface IIcoonProps {
        onClick?: (event: React.MouseEvent<HTMLElement>) => void;
    }
    

    Edit

    If you want a non-generic interface to work with then you can create your own and then use that:

    type MouseEvent = React.MouseEvent<HTMLElement>;
    
    interface IIcoonProps {
        onClick?: (event: MouseEvent) => void;
    }