Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Nested object in React functional component state with Typescript

I have an nested object in React functional component state, but I only can access first level of object if I use any type.

export default function Detail() {
    const [user, setUser] = useState<any>({});
    const { id } = useParams();


    useEffect(() => {
        fetch('http://localhost:4000/users/' + id)
        .then(response => {
            return response.json();
        })
        .then(data => {
            setUser(data);
        })
    }, []);
    
    

    return (
        <div>
            <h1>Detail view</h1>
            <p>ID: { user.id }</p>
            <p>First name: { user.first_name }</p>
            <p>Last name: { user.last_name }</p>
            <p>Email: { user.email }</p>
            <p>Gender: { user.gender }</p>
        </div>
    );
}

When trying to access user.company.name it throws

Detail.tsx:40 Uncaught TypeError: Cannot read properties of undefined (reading 'name')

I made an interface for it, but it gives me an error if I’m trying to use it for state type.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

interface UserInfo {
    id: number;
    first_name: string;
    last_name: string;
    email: string;
    gender: string;
    company: {
        name: string;
        department: string;
    }
}
Argument of type '{}' is not assignable to parameter of type 'UserInfo | (() => UserInfo)'.

How can I use defined interface as state type?

>Solution :

Don’t use the any type. TypeScript can’t help you if you don’t use actual types. Type the state narrowly.

Don’t use an empty object as your default value. It isn’t useful. Use a value that clearly indicates that the data isn’t available yet.


type PossibleUserInfo = UserInfo | null;

const [user, setUser] = useState<PossibleUserInfo>(null);

Then, handle the case where you don’t have the data yet explicitly.

It isn’t useful to spit out a div with a bunch of paragraphs containing a label but not data.


if (user) {
    return (
        <div>
            <h1>Detail view</h1>
            <p>ID: { user.id }</p>
            <p>First name: { user.first_name }</p>
            <p>Last name: { user.last_name }</p>
            <p>Email: { user.email }</p>
            <p>Gender: { user.gender }</p>
        </div>
    );
}

return (
    <div>
        <h1>Default view</h1>
        <Loading />
    </div>
);

… where Loading is a component that shows (for example) a loading spinner.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading