Typing a React function component in TypeScript

This article is in concept - almost done 😎

The project I'm currently working on is running on TypeScript. Since it's a greenfield project and it runs on React 16.8+, we strive to create the front-end by using only function components.

There's multiple arguments for using TypeScript, but the main reason is that we want to minimize the risk of us introducing bugs in our codebase. Other reasons for why we're running on TypeScript are listed below:

Why I use TypeScript

  • ✅ Strict type checking of React component props
  • ✅ Easier debugging of 3rd party packages
  • ✅ Strict checking of null values (prevent broken apps in runtime)
  • ✅ Know what parameter(s) a function expects and what it will return
  • ✅ Force consistent casing in filenames
  • ✅ Remove comments when compiling to JavaScript
  • 💡 ... and there's a lot more in the compiler options

All in all, using TypeScript with your React app will result in a more confident (and after a steep learning curve also a more comfortable) developer experience, especially when you're working in a complex environment.

A React component in JavaScript (.jsx)

/* ./src/components/navigation/Navigation.jsx */

// Import React
import React from "react"

// Define mock theme data
const theme = "dark"

// Define mock menu item data
const items = [
  {
    url: "/",
    text: "Home",
  },
  {
    url: "/blog",
    text: "Blog",
  },
  {
    url: "/contact",
    text: "Contact",
  },
  {
    url: "https://external.url",
    text: "External link",
    target: "_blank",
  },
]

// Create a React component
const Navigation = ({ theme, items }) => (
  <nav className={theme === "dark" ? "dark" : "light"}>
    {items.map((item) => (
      <a target={item.target && item.target} href={item.url}>
        {item.text}
      </a>
    ))}
  </nav>
)

// Export the Navigation variable so we can import it in other files
export default Navigation

In a production app the variables theme and items will be passed from another component to this one, but for now we're mocking the data so we can focus on implementing TypeScript.

A React component in TypeScript (.tsx)

/* ./src/components/navigation/Navigation.tsx */

// Import React
import React, { FunctionComponent } from "react"

// Import TypeScript types and enums
import {
  TNavigationProps,
  TNavigationItems,
  TNavigationItem,
  ThemeEnum,
} from "./navigationTypes.ts"

// Define mock theme data
const theme = ThemeEnum.Dark

// Define mock menu item data
const items: TNavigationItems = [
  {
    url: "/",
    text: "Home",
  },
  {
    url: "/blog",
    text: "Blog",
  },
  {
    url: "/contact",
    text: "Contact",
  },
  {
    url: "https://external.url",
    text: "External link",
    target: "_blank",
  },
]

// Create a React component
const Navigation: FunctionComponent<TNavigationProps> = ({ theme, items }) => (
  <nav className={theme === ThemeEnum.Dark ? "dark" : "light"}>
    {items.map((item: TNavigationItem) => (
      <a target={item.target && item.target} href={item.url}>
        {item.text}
      </a>
    ))}
  </nav>
)

// Export the Navigation variable so we can import it in other files
export default Navigation

/* ./src/components/navigation/navigationTypes.ts */

export TNavigationProps = {
  
}

export ThemeEnum {
  Dark = "dark"
  Light = "light"
}
This article is in concept - almost done 😎