Skip to main content

TypeScript Introduction

What is TypeScript?

TypeScript is a programming language developed and maintained by Microsoft. It is a superset of JavaScript, which means any valid JavaScript code is also valid TypeScript code. However, TypeScript extends JavaScript by adding static type definitions, allowing developers to define types for variables, function parameters, and return values.

TypeScript and JavaScript relationship

Why TypeScript?

JavaScript is dynamically typed, which means variables can change types during runtime. While this provides flexibility, it can lead to unexpected errors. TypeScript helps catch these errors during development rather than at runtime by introducing a type system.

Benefits of TypeScript

  • Early Error Detection: TypeScript can identify errors during development, before your code runs
  • Better IDE Support: Enhanced code completion, navigation, and refactoring
  • Improved Documentation: Types serve as documentation for your code
  • Safer Refactoring: Changing code becomes less risky
  • Enhanced Team Collaboration: Types make it easier to understand interfaces between components

TypeScript and Next.js

Next.js has built-in TypeScript support, making it an excellent framework for TypeScript-powered applications. Next.js projects can leverage TypeScript to create more maintainable, scalable applications with fewer runtime errors.

TypeScript Basics

Basic Types

TypeScript provides several basic types to annotate variables:

typescript
// Type annotations using ":"
let isDone: boolean = false;
let count: number = 42;
let name: string = "John";

// Arrays
let numbers: number[] = [1, 2, 3];
let names: string[] = ["Alice", "Bob", "Charlie"];

// Tuples (fixed-length arrays with specific types)
let person: [string, number] = ["Alice", 30];

// Enum
enum Color {Red, Green, Blue}
let favoriteColor: Color = Color.Blue;

// Any (avoid when possible)
let notSure: any = 4;
notSure = "maybe a string";
notSure = false;

// Void (absence of type, typically for functions that don't return a value)
function logMessage(): void {
console.log("This is a log message");
}

Interfaces

Interfaces define the structure of objects:

typescript
interface User {
id: number;
name: string;
email: string;
isActive?: boolean; // Optional property
}

// Using the interface
function createUser(user: User): void {
console.log(`Created user ${user.name} with ID ${user.id}`);
}

// This will work
createUser({
id: 1,
name: "John Doe",
email: "[email protected]"
});

// This will cause a TypeScript error
// Property 'email' is missing
// createUser({
// id: 2,
// name: "Jane Doe"
// });

Functions with Types

TypeScript allows you to specify types for function parameters and return values:

typescript
// Function with parameter types and return type
function add(a: number, b: number): number {
return a + b;
}

// Function type definition
type MathOperation = (x: number, y: number) => number;

// Using the function type
const multiply: MathOperation = (x, y) => x * y;
const result = multiply(5, 3); // 15

Real-World Example: Creating a Next.js Component

Here's a simple Next.js component using TypeScript:

tsx
import React from 'react';

// Define the props interface for our component
interface ProductCardProps {
id: number;
name: string;
price: number;
description?: string;
onAddToCart: (id: number) => void;
}

// Use the interface to type the component props
const ProductCard: React.FC<ProductCardProps> = ({
id,
name,
price,
description,
onAddToCart
}) => {
return (
<div className="product-card">
<h3>{name}</h3>
<p className="price">${price.toFixed(2)}</p>
{description && <p className="description">{description}</p>}
<button onClick={() => onAddToCart(id)}>Add to Cart</button>
</div>
);
};

export default ProductCard;

In this example:

  1. We define an interface ProductCardProps that describes the shape of our component's props
  2. We apply this interface to our functional component using React.FC<ProductCardProps>
  3. TypeScript ensures we use all required props and that they have the correct types
  4. The optional description property is handled with conditional rendering

Type Inference

TypeScript doesn't always require explicit type annotations because it can often infer types based on values:

typescript
// Type inference - TypeScript infers these types automatically
let message = "Hello"; // inferred as string
let count = 10; // inferred as number
let isValid = true; // inferred as boolean

// TypeScript will catch type errors even with inferred types
// message = 42; // Error: Type 'number' is not assignable to type 'string'

Getting Started with TypeScript in a Next.js Project

Setting up a new Next.js project with TypeScript

bash
npx create-next-app@latest my-typescript-app --typescript

Adding TypeScript to an existing Next.js project

  1. Install TypeScript and related dependencies:
bash
npm install --save-dev typescript @types/react @types/node
  1. Create a tsconfig.json file (Next.js will populate it on the next run):
bash
touch tsconfig.json
  1. Run your Next.js development server:
bash
npm run dev
  1. Start converting .js files to .tsx (for components) or .ts (for non-React files)

TypeScript Configuration for Next.js

A typical tsconfig.json for a Next.js project might look like this:

json
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"baseUrl": ".",
"paths": {
"@/*": ["*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

Common TypeScript Patterns in Next.js

Typing API Routes

typescript
// pages/api/users.ts
import type { NextApiRequest, NextApiResponse } from 'next';

type User = {
id: number;
name: string;
}

export default function handler(
req: NextApiRequest,
res: NextApiResponse<User[] | { message: string }>
) {
if (req.method === 'GET') {
const users: User[] = [
{ id: 1, name: 'John' },
{ id: 2, name: 'Jane' }
];
res.status(200).json(users);
} else {
res.status(405).json({ message: 'Method not allowed' });
}
}

Typing Page Props with GetServerSideProps

typescript
// pages/products/[id].tsx
import { GetServerSideProps } from 'next';

interface Product {
id: number;
name: string;
price: number;
}

interface ProductPageProps {
product: Product | null;
}

export const getServerSideProps: GetServerSideProps<ProductPageProps> = async (context) => {
const { id } = context.params || {};

try {
const res = await fetch(`https://api.example.com/products/${id}`);
const product: Product = await res.json();

return {
props: { product }
};
} catch (error) {
return {
props: { product: null }
};
}
};

export default function ProductPage({ product }: ProductPageProps) {
if (!product) {
return <div>Product not found</div>;
}

return (
<div>
<h1>{product.name}</h1>
<p>Price: ${product.price.toFixed(2)}</p>
</div>
);
}

Summary

TypeScript is a powerful extension of JavaScript that adds static typing to help catch errors early and enhance the development experience. When used with Next.js:

  • It helps prevent common errors through type checking
  • It improves code readability and maintainability
  • It provides better IDE support and tooling
  • It enhances the documentation of your code implicitly through types

By learning TypeScript, you're investing in skills that will make you more productive and help you build more robust applications with Next.js.

Additional Resources

Practice Exercises

  1. Convert a simple JavaScript function to use TypeScript types.
  2. Create a Next.js page component with typed props.
  3. Define an interface for a user object and create functions that operate on it.
  4. Build a simple form component in Next.js with TypeScript validation for the form data.
  5. Create a custom hook in TypeScript that manages a counter state.

Happy coding with TypeScript and Next.js!



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)