Setting State without default value
Things can get a little tricky when we don't have a default value to start out with. TypeScript can't help up out and make any assumptions on our behalf. Let's consider this code for a moment.
import { useEffect, useState } from "react";
import Quotes from "./quotes";
import InspirationalQuote from "./quote";
import Loading from "./loading";
export type Quote = {
id: number;
content: string;
source?: string;
};
export const fetchRandomQuote = async () => {
const response = await fetch(`/api/quotes/random`);
return response.json();
};
export const fetchQuotes = async (count: number) => {
const response = await fetch(`/api/quotes?limit=${count}`);
return response.json();
};
const Application = () => {
const [quote, setQuote] = useState();
useEffect(() => {
fetchRandomQuote().then(setQuote);
}, []);
if (!quote) return <Loading />;
return (
<main className="w-full max-w-2xl py-16 mx-auto">
{/* <InspirationalQuote content={quote.content} source={quote.source} /> */}
{/* <Quotes>
<div className="grid grid-cols-2 gap-4"></div>
</Quotes> */}
</main>
);
};
export default Application;
It doesn't even matter what the InspirationalQuote is just yet or what properties it takes.
Look at this:
const [quote, useQuote] = useState();
The type is inferred as:
const quote: undefined;
Well, we're passing undefined to useState. If TypeScript was smart enough to assume that the number we passed to the useState in our counter example meant that count was a number, then the logic follows that quote is of the type undefined.
Solving the problem
Okay, so enough complaining—what are we going to do about it?
Using an empty value
So, what do we do? We have a few options:
We could give it an empty value (e.g. { content: '', source: '' });
const [quote, setQuote] = useState({ content: "", source: "" });
This works, but it has two problems:
- We broke our loading functionality since
!quotewill never be a case. - It's not totally clear to TypeScript that
sourceis optional.
Providing a type variable
We could also step in and help TypeScript out a bit by providing a type variable. If you hover over useState you'll see something that starts with:
useState<{
content: string;
source: string;
}>;
Well, we can step in and provide that service for TypeScript.
const [quote, setQuote] = useState<Quote | undefined>();