code snippets

VERY BASIC: How TypeScript Works In Next.js

If you're writing and building React/Next.js applications you'll need to use TypeScript. Period. Don't fight learning TypeScript, just steer into it.
Long story short: The props you pass to a child component need to be defined (or "typed") so that it knows what to expect when it runs. Check out the example below:


1//Dashboard component:
2//... import all external files here, we're just focused on the ProductButton
3import ProductButton from "@/components/product-button";
4
5//code will not wrap if too long, scroll sideways to view all code
6export default async function Dashboard() {
7    return (
8        <main>
9            <div className="grid md:grid-cols-3 md:grid-rows-[45px_1fr] grid-rows-[45px_300px_500px] gap-3 md:h-[600px]">
10                <div className="relative md:row-start-2 md:row-span-full md:col-start-1 md:col-span-1">
11                    <ProductList />
12                    <div className="absolute bottom-6 right-6">
13                        <ProductButton actions="add"/>
14                    </div>
15                </div>
16                <div className="md:row-start-1 md:row-span-full md:col-start-2 md:col-span-full">
17                    <ProductDetails />
18                </div>
19            </div>
20        </main>
21    );
22}

1//the ProductButton component
2//code will not wrap if too long, scroll sideways to view all code
3type ProductButtonProps = {
4    actions: "add" | "edit" | "checkout";
5    children?: React.ReactNode;
6    onClick?: () => void;
7}
8
9export default function ProductButton({actions, children, onClick}:ProductButtonProps) {
10    if (actions === "add") {
11        return (
12            <Button variant="default" color="rgba(0, 0, 0, 1)" className="flex rounded-full border h-15 w-15">
13                <ModalAddProduct action={actions} />
14            </Button>
15        )
16    }
17
18    if (actions === "edit") {
19        return <Button variant="default" radius="lg" color="rgba(0, 0, 0, 1)"><ModalAddProduct action={actions} /> </Button>
20    }
21
22    if (actions === "checkout") {
23        return <Button variant="default" radius="lg" color="rgba(0, 0, 0, 1)" onClick={onClick}>{children}</Button>
24    }
25}

Summary: Don't get overwhelmed with all of that code.... FOCUS GRASSHOPPER!

Dashboard component:
Do you see where we invoke the ProductButton component (<ProductButton actions="add"/>)? That's all you should be paying attention to at the moment. See the "actions" prop on the ProductButton? That's our target - in this case it's set to "add"....

ProductButton component:
The "type ProductButtonProps = {...." structure at the top of the file defines what our passed in props should "look like", or specifically, what type of data those individual attributes should represent (are they numbers? strings? dates? french fries.... just kidding - but not really - in a future post I'll describe how you can customize these prop thingies even more).

Making TypeScript make sense:
If you've been struggling with how to use TypeScript in your Next.js project, right here is where you'll finally understand how to make it work for you. Copy and paste the two components from this page into your local Next.js project (make sure to name them Dashboard.tsx and ProductButton.tsx and locate them inside of your project). Do what you have to just to get the components to run and display without any errors.

Suppose you were extending the functionality of what your ProductButton component does (in this case adding refunds). Now, in the Dashboard component where we invoke the ProductButton component, change

<ProductButton actions="add"/>
to
<ProductButton actions="refund"/>

You should immediately notice your IDE (VSCode, Webstorm, etc) complains with an error. Why? Because in the ProductButton component:

type ProductButtonProps = {
actions: "add" | "edit" | "checkout";
children?: React.ReactNode;
onClick?: () => void;
}


...you told your ProductButton component that it should only expect the values "add" OR "edit" OR "checkout", and that"s TypeScript in action! It checks your "types" for you and tells you when there's an issue.

To complete our task of adding "refund" functionality simply add "refund" to the ProductButton component prop type definition at the top of ProductButton.

Change
action: "add" | "edit" | "checkout"
to
actionType: "add" | "edit" | "checkout" | "refund"

TypeScript will look at both files, reading back and forth and analyze what your component is actually passing and receiving for props.

TypeScript will keep your code honest during development as well as at build time (ignoring a TypeScript error that you made during coding will throw that same error during the build process so you better fix it!)