DEV Community

Cover image for Create an Avatar Component in Gatsby with TypeScript Part 3: Adding Types
Joel Turner
Joel Turner

Posted on • Originally published at joelmturner.com

1 3

Create an Avatar Component in Gatsby with TypeScript Part 3: Adding Types

We left off with our avatar component working using Gatsby Image and still able to receive an image URL. Now, let's look at what it would take to type this component. I like to use type instead of interface for the props. You can read more about the difference between type and interface if you'd like.

The props type will look something like this:

{...}
type AvatarProps = {
  url?: string;
  altText?: string;
  title?: string;
  user?: "monster1" | "monster2";
}

function Avatar(props: AvatarProps) {
{...}
Enter fullscreen mode Exit fullscreen mode

The cool part here is that the user prop can be typed to match the graphql alias names. This helps anyone consuming this component know the values they can pass.

Let's take a look at typing our data variable. We know the shape of what we expect because of our graphql. We just need to provide the correct typing at the childImageSharp level. Luckily Gatsby Image has a type of FixedObject that can help us out here. We pass the type to the static query hook useStaticQuery<Data>(graphql to signify that we expect the return to be Data.

{...}
import Img, { FixedObject } from "gatsby-image"
{...}

type Data = {
  monster1: {
    childImageSharp: {
      fixed: FixedObject;
    };
  };
  monster2: {
    childImageSharp: {
      fixed: FixedObject;
    };
  };
}

function Avatar(props: AvatarProps) {
  const data = useStaticQuery<Data>(graphql`
{...}
Enter fullscreen mode Exit fullscreen mode

Let's refactor the redundancy in the Data type.

type ChildImage = {
  childImageSharp: {
    fixed: FixedObject;
  };
}

type Data = {
  monster1: ChildImage;
  monster2: ChildImage;
}
Enter fullscreen mode Exit fullscreen mode

Cool, now we should have something like this:

import React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Img, { FixedObject } from "gatsby-image"

type AvatarProps = {
  url?: string;
  altText?: string;
  title?: string;
  user?: "monster1" | "monster2";
}

type ChildImage = {
  childImageSharp: {
    fixed: FixedObject;
  };
}

type Data = {
  monster1: ChildImage;
  monster2: ChildImage;
}

function Avatar(props: AvatarProps) {
  const data = useStaticQuery<Data>(graphql`
    query {
      monster1: file(relativePath: { eq: "monster-01-headshot.png" }) {
        childImageSharp {
          fixed(width: 75, height: 75) {
            ...GatsbyImageSharpFixed
          }
        }
      }
      monster2: file(relativePath: { eq: "monster-02-headshot.png" }) {
        childImageSharp {
          fixed(width: 75, height: 75) {
            ...GatsbyImageSharpFixed
          }
        }
      }
    }
  `)

  const { url, altText, title, user } = props
  const styles = {
    width: "75px",
    height: "75px",
    borderRadius: "50%",
  }

  if (url) {
    return <img style={styles} src={url} alt={altText} title={title} />
  }

  return <Img style={styles} fixed={user && data[user].childImageSharp.fixed} alt={altText} title={title} />
}

export default Avatar
Enter fullscreen mode Exit fullscreen mode

There we go! Now our avatar component is ready for prime time. Please let me know if you have any questions or would like to share other ways to solve the same requirements. Thanks for following along!

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay