How do I create a TypeScript type definition for a stateless React component?
Asked Answered
H

6

31

I'm trying create type definitions for an existing suite of stateless React components, so I can generate documentation automagically and to improve intellisense in my team's tooling.

An example component could look like this:

myComponent.js

import React from 'react';

export const MyComponent = ({ prop1, prop2, prop3 }) => (
    <div>
        { prop1 ? prop2 : prop3 }
    </div>
);

I would like my type definition to:

  • Define which props are allowed (and which are required)
  • That it will return JSX

Looking at this example of creating React components using TypeScript, I discovered the type: React.SFC.

I tried to use this in my definition:

index.d.ts

declare module "MyComponent" {
    import React from 'react';

    interface MyComponentProps {
        prop1: boolean;
        prop2?: string;
        prop3?: string;
    }

    export const MyComponent = React.SFC<MyComponentProps>
}

But I'm getting the linting error [ts] '(' expected.

I'm pretty new to TypeScript and I am clearly missing something, but I can't find any articles on creating type definitions for stateless components.

EDIT To be clear, I don't want to rewrite my components in TypeScript. I want to create a type definition file (*.d.ts) for an existing ES6 stateless component.

Hartzell answered 20/6, 2018 at 11:18 Comment(0)
H
39

After a lot of fiddling, we have settled on the following set up.

import React from 'react';

export interface MyComponentProps {
    prop1: boolean;
    prop2?: string;
    prop3?: string;
}

declare const MyComponent: React.SFC<MyComponentProps>

export default MyComponent

The inspiration for this was taken from: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/material-ui/index.d.ts

It works well with TypeDoc and also VS Code's intellisense.

I believe export default was the key to cracking intellisense here.

Hartzell answered 28/7, 2018 at 17:50 Comment(6)
What file did you put this in, and where is that file in your project?Dramatist
I our case, the file was named "index.d.ts", which matches the dist/index.js file in question.Hartzell
But you can define the typing file in your package.json, like so: "typings": "index.d.ts"Hartzell
How do you guys would do to add a type annotation file to a functional component with state (using useState)?Seth
I don't think the type definition would change, unless the props changed?Hartzell
That was really helpful, i was stuck on that declare module thing that wouldn't produce anything good, now i can type all these sh*tty components without having to rewrite them all! Thanks a bunch 🙏Lastditch
O
13

Try this:

declare module "MyComponent" {
  import React from 'react';

  interface MyComponentProps {
    prop1: boolean;
    prop2?: string;
    prop3?: string;
  }

  export const MyComponent: (props: MyComponentProps) => React.SFC<MyComponentProps>
}

From official React page recommendations Type Definitions

Opuntia answered 20/6, 2018 at 14:9 Comment(1)
You are declaring a HOC, a function that returns a stateless functional componentRibaudo
H
2

I think you need var MyComponent: React.SFC<MyComponentProps>;

You might consider rewriting existing code in typescript anyway just to see what kind of definitions tsc would generate. Then discard the code and keep just the definitions.

Haematozoon answered 20/6, 2018 at 12:45 Comment(1)
If I define: var MyComponent: React.SFC<MyComponentProps>; Will the be automatically exported? Ah that's a cool idea - I didn't realise TypeScript would output something which was human readable.Hartzell
D
1

Its, :, not =.

export const MyComponent:React.SFC<MyComponentProps> = ({ prop1, prop2, prop3 }) => (
<div>
    { prop1 ? prop2 : prop3 }
</div>
);
Depose answered 20/6, 2018 at 12:21 Comment(1)
I've updated my question, but I think this is rewriting the component in typescript. I am looking to write a type definition for an existing ES6 component.Hartzell
W
-2

I am using react typescript react boilerplate provided by Microsoft https://github.com/Microsoft/TypeScript-React-Starter

I create a stateless component in typescript like this:

export interface IMyComponentProps {
   prop1: string;
   prop2: (event: React.MouseEvent) => void;
   prop3: number;
}

export class MyComponent extends React.Component<IMyComponentProps> {
    render(): JSX.Element {
        const {prop1, prop2} = this.props

        return (
            //My code here
            <button>prop1</button>
            <button>prop2</button>
        );
    }
}
Warram answered 20/6, 2018 at 12:11 Comment(3)
This answer shows how to create a stateless component, rather than a stateless component type definition file.Hartzell
This is how to write it in ts not how to declare a definition as the question asks.Vc
I have initialized interface for the same.Warram
S
-3

You can try something like this.

export type YourComponentType = {
  props1,
  props2
}

const YourComponent = ({
  props1,
  props2,
  ...restProps //additional props if passed to components.
}: YourComponentType) => (
  <div>{props1}</div>
)

export default YourComponent;
Schulein answered 20/6, 2018 at 12:23 Comment(1)
Unless I'm missing something, I think this is an example of rewriting the component itself. I'd like to create a .d.ts file for an existing ES6 module. I've updated my questionHartzell

© 2022 - 2024 — McMap. All rights reserved.