Posted on: Written by: K-Sato
⚠️ This article was posted over 2 years ago. The information might be outdated. ⚠️

Table of Contents

Types or Interfaces?

Interfaces are different from types in TypeScript, but they can be used for very similar things as far as common React uses cases are concerned. Here’s a helpful rule of thumb:

  • always use interface for public API’s definition when authoring a library or 3rd party ambient type definitions.

  • consider using type for your React Component Props and State, because it is more constrained.

  • Types or Interfaces?

Hooks

UseState

Many hooks are initialized with null-ish default values, and you may wonder how to provide types. Explicitly declare the type, and use a union type.

const [user, setUser] = React.useState<IUser | null>(null)

Define types in one file

Make a file called file_name.d.ts and defines all the types there.

Add types to props

import React from 'react' // we need this to make JSX compile

type CardProps = {
  title: string
  paragraph: string
}

export const Card = ({ title, paragraph }: CardProps) => (
  <aside>
    <h2>{title}</h2>
    <p>{paragraph}</p>
  </aside>
)
const el = <Card title="Welcome!" paragraph="To this example" />

Pass an array

interface cardProps {
  issues: {
    id: string
    paragraph: string
  }[]
}

Make properties optional

If you want to make some properties optional, do that in the respective Props type:

type CardProps = {
  title: string,
  paragraph?: string  // the paragraph is optional
}

Use a hook in map function

When you get the error below, remember the code!

./src/components/molecules/messageClient/Item/index.tsx
  Line 21:  React Hook "useDeactivateTokenMutation" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function  react-hooks/rules-of-hooks

Search for the keywords to learn more about each error.
import React from 'react'
import { useDeleteMutation } from '../../../../generated/graphql'

interface Props {
  name: string
  tokens: string[]
}

const Item = ({ name, tokens }: Props) => {
  const DeleteMutation = useDeleteMutation()
  return (
    <div>
      <div>
        {name}
        <ul>
          {tokens.map(token => (
            <li>
              {token}
              <button
                onClick={() => {
                  DeleteMutation({ variables: { token } })
                }}
              >
                Delete
              </button>
            </li>
          ))}
        </ul>
      </div>
    </div>
  )
}

export default Item

Typing Functions in TypeScript

Method Signatures

The method signature syntax is probably the most straightforward to use. When defining an object type, its methods can easily be described by providing signatures as follows:

interface Date {
  toString(): string
  setTime(time: number): number
  // ...
}

Function Type Literals

Function type literals are another way to declare the type of a function. They’re typically used in the signature of a higher-order function, that is, a function which accepts functions as parameters or which returns a function:

interface Array<T> {
  sort(compareFn?: (a: T, b: T) => number): this
  // ...
}

TypeScript and React: Events

You either need to be specific with e.g. React.MouseEvent or import the MouseEvent typing right from the React module:

import React, { Component, MouseEvent } from 'react'

export class Button extends Component {
  handleClick(event: MouseEvent) {
    event.preventDefault()
    alert(event.currentTarget.tagName) // alerts BUTTON
  }

  render() {
    return <button onClick={this.handleClick}>{this.props.children}</button>
  }
}

Events supported are: AnimationEvent, ChangeEvent, ClipboardEvent, CompositionEvent, DragEvent, FocusEvent, FormEvent, KeyboardEvent, MouseEvent, PointerEvent, TouchEvent, TransitionEvent, WheelEvent. As well as SyntheticEvent, for all other events.

Form example

import React, { useContext, MouseEvent } from 'react'

interface FormElements extends HTMLFormControlsCollection {
  email: HTMLInputElement
}

const CreateUser = () => {
  const handleSubmit = (e: MouseEvent<HTMLFormElement>): void => {
    e.preventDefault()
    const { email } = e.currentTarget.elements as FormElements
    createUser({ email: email.value })
  }

  return (
    <>
      <form noValidate onSubmit={handleSubmit}>
        <TextField required label="Email Address" name="email" type="email" />
        <Button type="submit">Create a New User</Button>
      </form>
    </>
  )
}

export default CreateUser

React onClick - pass event with parameter

If you want to pass e(event) as a paramter in an input, you can do so like the following example.

function clickMe(event, someParameter){
     //do with event
}
<button onClick={(e) => {
     this.clickMe(e, someParameter)
}}>Click Me!</button>
And in your function:

Typescript input onchange event.target.value

You can use React.ChangeEvent<HTMLInputElement>.

onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
  const newValue = e.target.value
}

References

About the author

I am a web-developer based somewhere on earth. I primarily code in TypeScript, Go and Ruby at work. React, RoR and Gin are my go-to Frameworks.