Cover image for ❤ TypeScript with React

❤ TypeScript with React

Thu Jul 07 2022

TypescriptReact JsJSX

🔌 Props are a means of contact.

The central feature of React is the components. It helps us to have a real separation of concepts. We need many of them to build a complete UI, so we have to make them interact.

The simple way to move data from one component to another is through props:

import React from 'react'

import Post from './Post'

export default function FirstPost({ post }) {
  return (
    <>
      <Post title={post.title} description={post.description} />
    </>
  )
}

This is a typical pattern: a component gets information from props, uses other components, and provides them with props. The FirstPost component here uses the Post component. To provide information from FirstPost to Post, we use props. It is a means of communication and should be seen as such by developers.

What then is a perfect contact medium? It's not so much the ability to connect, but the UX features surrounding it.

To talk to some friends, I use WhatsApp. I can send and receive messages, of course, but what are the features we have around that? To know if my message has been read, I saw the blue check, great. I don't have the possibility to edit my message, I don't like it at all (long live Telegram) What about React props? You can assign a value to a component, ok, but what developer experience do we have around this? Type check

Types can strengthen the DX (Developer Experience) because when something is wrong, it can alert us. Using prop types is the normal way to add type checks to our props.

import React from "react";
import PropTypes from "prop-types";

const Post = ({ title, description = "" }) => {
  return (
    <div className="px-6 py-2 rounded shadow-sm">
      <h2 className="text-2xl font-bold">{title}</h2>
      {description && (
        <p className="text-sm">{description}</p>
      )}
    </div>
  );
};

Post.propTypes = {
  title: PropTypes.string.isRequired,
  description: PropTypes.string
};

export default Post

Great, we can communicate more efficiently, as we can decide whether a prop is required or not, whether it is a string or another type, or even give a strict list of possible values!

😎 TypeScript gets in on the action

The prop-types library was included in React before React v15.5. The React team took the option of removing it from the core, true to their ideology of providing an unpopular library, to allow developers to use other typing systems, such as Flow or TypeScript. The latter, let's give it a try.

One of TypeScript's entry hurdles is that the tool has to be built and configured before you can use it. It's not as easy as yarn add prop-types, no doubt. In my opinion, the best way to learn TypeScript is to skip this step entirely. Just build a new React application with CRA, and let's start learning!

Local dev setups:

Next.js: npx create-next-app@latest --ts will create in your current folder
Create React App: npx create-react-app name-of-app --template typescript will create in new folder
Vite: npm create vite@latest my-react-ts-app -- --template react-ts
Meteor: meteor create --typescript name-of-my-new-typescript-app
Ignite for React Native: ignite new myapp
TSDX: npx tsdx create mylib for Creating React+TS libraries. (in future: TurboRepo)

Created. Now, in our component, let's switch from PropTypes to TypeScript.

import * as React from "react";

interface Props {
  title: string
  description?: string
}

const Post = ({ title, description = "" }: Props): JSX.Element => {
  return (
    <div className="px-6 py-2 rounded shadow-sm">
      <h2 className="text-2xl font-bold">{title}</h2>
      {description && (
        <p className="text-sm">{description}</p>
      )}
    </div>
  );
};

export default Post

The magic of TypeScript is that the types and interfaces we have are not only available exclusively. To deduce the knowledge, it also analyzes our code.

TypeScript also comes with a little extra: you can do it right in the code editor when you're developing. To get hints from a function, you don't have to wait for them to run in the browser, as was the case with prop types.

Now that we are at it, let's also change our component:

import * as React from 'react'

import Post from './Post'

interface Props {
  post: {
    title: string
    description?: string
  }
}

export default function SinglePost({ post }: Props) {
  return (
    <>
      <Post title={post.title} description={post.description} />
    </>
  )
}

But what happens when we want to receive a string that can only be small, medium or large for example for the size of the photo of the post? Well, let's see the following code and how TypeScript acts with the validation:

import * as React from 'react'

import Post from './Post'

interface Props {
  post: {
    title: string
    description?: string
    imageSize: "small" | "medium" | "large"
  }
}

export default function FirstPost({ post }: Props): JSX.Element {
  return (
    <>
      <Post title={post.title} description={post.description} />
    </>
  )
}
import * as React from 'react'

interface Props {
  title: string
  description?: string
  imageSize: 'small' | 'medium' | 'large'
}

const Post = ({ title, description = '', imageSize }: Props): JSX.Element => {
  return (
    <div className="px-6 py-2 rounded shadow-sm">
      <h2 className="text-2xl font-bold">{title}</h2>
      {description && <p className="text-sm">{description}</p>}
      <img src="https://picsum.photos/200/300" alt={title} className={imageSize} />
    </div>
  )
}

export default Post

When adding the new prop and opening the quotes we will notice that TypeScript is now autocompleting the possible sizes that can be passed to it and additionally tells us that we must pass the correct prop because otherwise, it does not correspond to the types that were declared.

And what's really cool is that TypeScript is not restricted to props parts, unlike PropTypes. All of our JavaScript code, even what is not connected to our React components, can have alerts. Even what is not fully connected to the front-end, because TypeScript works with NodeJS like a charm.

Now, in our code, we can be sure.

🧐 Conclusions.

I'm not going to lie, the road is not easy with TypeScript and sometimes the learning curve can be tough. But it's certainly worth it, I guess (?) 😂.

By proposing an open-source tool that is responsive to JavaScript advances, Microsoft has done a great job. This new quasi-standard has been embraced by the JS ecosystem, and many libraries are compatible with TypeScript to allow us to do our code, as we did in our examples with React's JSX.Element.

It was a gamble for me to be able to get into TypeScript some time ago, and I was always losing. Now in 2021? It's a pretty obvious bet. Today, use it! You won't regret it.

Oh and if I forgot to tell you JSX.Element is a way to tell TypeScript that what that function returns is JSX > and it doesn't need to do anything else.

I see you in the 👨💻 code.