lomine
lomine

Reputation: 1181

React Typescript how to pass props with types

Trying to get better with Typescript in React

I have a super simple app where I have App.tsx with a useState for an array of objects

import List from './components/List';

interface IState{
  name: string
  age: number
}

function App() {

  const [people, setpeople] = useState<IState[]>([
    {
      name: 'Chris',
      age: 20
    },
    {
      name: 'John',
      age: 28
    },
    {
      name: 'Paul',
      age: 23
    }
  ])

  return (
    <div className="App">
      <List people={people}/>
    </div>
  );
}

export default App;

I want to pass this as a prop into another component List.tsx.

interface IProps{
    name: string
    age: number
  }

const List = (people:IProps[]) => {
    return (
        <div>
            {people.map(person => (
                <h2>{person.name}</h2>
            ))}
        </div>
    );
};

export default List;

I have types for the object in App.tsx and I'm trying to use the same types in List.tsx

The problem in App.tsx at <List people={people}/> on people I get

Type '{ people: IState[]; }' is not assignable to type 'IntrinsicAttributes & IProps[]'.
  Property 'people' does not exist on type 'IntrinsicAttributes & IProps[]'

How do I pass the data in the prop with types ?

Upvotes: 2

Views: 6334

Answers (3)

Youssouf Oumar
Youssouf Oumar

Reputation: 46291

One way to fix your issue is to export the IState from App.tsx and import in List, and use it like so:

import { IState } from "../App"; // use the corect path

interface IProps {
  people: IState;
}

const List = ({ people }: IProps) => {
  return (
    <div>
      {people.map((person) => (
        <h2>{person.name}</h2>
      ))}
    </div>
  );
};

export default List;

Here is how you would export the interface in App.tsx:

export interface IState{
  name: string
  age: number
}

Upvotes: 0

Terry
Terry

Reputation: 66228

That is because props is the top level object that contains all props passed into the component, so you should either destructure it, or change the interface:

Quick fix: destructure props

const List = ({ people }: { people: IProps[] }) => { ... }

Better fix: Change the typing of IProps so It defines the nested people key

interface IProps{
    people: Array<{
        name: string;
        age: number;
    }>
}

const List = ({ people }: IProps) => { ... }

Suggestion

Some additional tip: instead of declaring the same prop interface across two files, which means you need to update them in multiple locations should you change your mind later, you can always make List export the people prop (or actually, the atomised version, say IPerson) and then let the consuming parent import it instead. An example:

// List.tsx
export interface IPerson {
    name: string;
    age: number;
}
interface IProps {
    people: IPerson[];
}
const List = ({ people }: IProps) => { ... }

Then...

// App.tsx
import List, { IPerson } from './components/List';
const [people, setpeople] = useState<IPerson[]>([ ... ]);

Upvotes: 5

Lahcen
Lahcen

Reputation: 1423

You can export your interface in the first file, and then import it in the second file

export interface IState{
  name: string
  age: number
}

And the to use the same interface in List.tsx.,

import { IState} from './List';

Upvotes: 1

Related Questions