Typescript:: Assigning data to a variable of type 'non empty array'

Viewed 61

I am a beginner and learning TypeScript for a week now. I have below code in my React Component

 interface Restaurant {
  id: number;
  name: string;
  rating?: number;
}

type NonEmptyArray<T> = [T, ...T[]];

type RestaurantProps = {
  data: NonEmptyArray<Restaurant>;
};

export const Restaurants: React.FC<RestaurantProps> = ({ data }) => {
  if (!data.length) {
    return null;
  }
  // by default, select the first element in the array
  // since it depends on first element, making sure that NonEmptyArray is passed 

  const [selectedRestaurant, setSelectedRestaurant] = React.useState(data[0]);
.....
}

Above code works fine and no typescript errors are shown.

Now, in my Jest Test, I am assigning my test data to a variable. I get below error

Type 'Restaurant[]' is not assignable to type 'NonEmptyArray'. Source provides no match for required element at position 0 in target. ts(2322)

const data: NonEmptyArray<Restaurant> = [ {id: 1, name: 'abc', rating: 3}, {id: 2, name: 'xyz', rating: 4}, {id: 3, name: 'pqr', rating: 3} ];

it('renders properly', () => {
    render(<Restaurants data={data} />);
    ....
});

Can someone help me understand if my approach is right? If so, how can fix this typescript error?

1 Answers

I think it might be worth simplifying your types a little bit:

// Restaurants.tsx

import { useState } from 'react';

import type { FC } from 'react';

// export your type so you can use it in your test file
 export interface Restaurant {
  id: number;
  name: string;
  rating?: number;
}

// It's common practice to use interfaces for object types
interface RestaurantProps {
// By not making data optional you are already requiring this prop in your component.
  data: Restaurant[];
};

export const Restaurants: FC<RestaurantProps> = ({ data }) => {
  // Having this check will ensure your component doesn't get rendered if your data array as no length.
  if (!data.length) {
    return null;
  }
  
  // Here you can return whatever you'd like.
  return <>data[0].name</>
}

In your Restaurants.jest.tsx file:

// Restaurant.jest.tsx

import { Restaurants } from './Restaurant.tsx';

import type { Restaurant } from './Restaurant.tsx';

const data: Restaurant[] = [ {id: 1, name: 'abc', rating: 3}, {id: 2, name: 'xyz', rating: 4}, {id: 3, name: 'pqr', rating: 3} ];

it('renders Restaurant', () => {
    render(<Restaurants data={data} />);
    ...
});

I hope this helps a little! Let me know if you have additional questions, I'd be glad to help out.

Related