Typescript Interesting Types
 Photo by Nijwam Swargiary
Photo by Nijwam SwargiaryThese days I'm building a new project to understand some topics deeply. It is about user experience, web performance, accessibility, and a type system for consistent data.
This project I'm basically using React with Typescript. At first, I implemented a custom hook to handle the data fetching. One of the possible data types the fetch could return is a Product type. It looks like this:
type Product = {
  name: string;
  price: number;
  imageUrl: string;
  description: string;
  isShippingFree: boolean;
  discount: number;
};
Now that I could fetch some products, I wanted to use the list of products to render in the DOM. So I created a Product component. But as we are using Typescript, the props should be typed. In this case, I used the Product type. It looks like this:
export const Product = ({
  imageUrl,
  name,
  description,
  price,
  discount,
  isShippingFree,
}: ProductType) => (
  <Box>
    <Image imageUrl={imageUrl} imageAlt={name} />
    <TitleDescription name={name} description={description} />
    <Price price={price} discount={discount} />
    <Tag label="Free Shipping" isVisible={isShippingFree} />
  </Box>
);
And when I started implementing the Image component, I just passed the imageUrl and the imageAlt as props. It looks like this:
export const Image = ({ imageUrl }) => <img src={imageUrl} />;
In this case, I couldn't use the Product type. But I could reuse it.
I learned about this new type: the Partial type. The idea of the Partial type is to build a new type based on the passed type and set all attributes to optional.
So, if we do a partial of the Product type, it would look like this:
type Product = {
  name?: string;
  price?: number;
  imageUrl?: string;
  description?: string;
  isShippingFree?: boolean;
  discount?: number;
};
All properties are set to optional.
And now I can use it for the Image component:
export const Image = ({ imageUrl }): Partial<ProductType> => (
  <img src={imageUrl} />
);
But when I use the Image component, I can pass any props I want. I miss the type check. It doesn't break in compile time.
To fix that, I could just build an ImagePropsType and use it as the component props type.
type ImagePropsType = {
  imageUrl: string;
};
export const Image = ({ imageUrl }): ImagePropsType => <img src={imageUrl} />;
But I already have the type for the imageUrl inside the Product type. So I started to search how I could reuse the type: I found the Pick type.
The Pick type lets me reuse the Product type by picking a set of properties I want:
type ImagePropsType = Pick<ProductType, 'imageUrl'>;
Now I ensure that type checking and the type reusability work well.
To build the whole Image component, I also needed to pass other props like: imageAlt and width.
What I wanted is the intersection of the Pick<ProductType, 'imageUrl'>, the imageAlt type, and the width type.
In Typescript, the representation of the intersection is the & operator.
I defined the ImageUrlType:
type ImageUrlType = Pick<ProductType, 'imageUrl'>;
And the ImageAttrType to represent both the imageAlt and the width:
type ImageAttrType = { imageAlt: string; width?: string };
And compose them together by insecting the types:
type ImagePropsType = ImageUrlType & ImageAttrType;
And the final result is:
import { ProductType } from 'types/Product';
type ImageUrlType = Pick<ProductType, 'imageUrl'>;
type ImageAttrType = { imageAlt: string; width?: string };
type ImagePropsType = ImageUrlType & ImageAttrType;
export const Image = ({ imageUrl, imageAlt, width }: ImagePropsType) => (
  <img src={imageUrl} alt={imageAlt} width={width} />
);
I have the image URL, alt, width types intersected, and defined in the ImagePropsType. It can think of types as data and compose them. This is a very cool feature.
These are the interesting new types I learned this week.