Table of Contents
Table of Contents
- Introduction
- Why TS is worth learning?
- Basic Types
- Type inference
- Union and Literal types
- Optional and readonly properties
- Arrays and tuples
- Generic Types
- Typing props and state
- Typing hooks
- Typing event handlers
- Conclusion
Introduction
Hey everyone!
I’ve been using TypeScript in a few of my projects lately, and I thought—why not put together a quick cheat sheet of the essentials? It’s meant to be a simple reference for when you need a quick refresher or just want a high-level overview.
Why TS is worth learning
While it's completely possible to use React without TypeScript, adding TS brings some powerful benefits. For one, it acts like built-in documentation — making it easier for developers (including your future self) to understand what types are being used without digging through definitions.
It also helps catch errors during development, especially at compile time, and can highlight unexpected changes in API responses early on — saving you from runtime bugs and headaches later.
Basic Types
Let's get started. These are some of the most commonly used types in TypeScript:
String:
let name: string = "TypeScript Essentials";
Type inference
TypeScript has this neat trick where it can figure out the type of a variable just by looking at the value you assign to it.
Example:
let age = 31; // TypeScript knows this is a number
let name = "Richie"; // TypeScript knows this is a string
In this example, TypeScript automatically understands that age is a number and name is a string based on the values assigned to them. This keeps your code clean and easy to read.
Hover Over JSX Elements:
If you are using an editor like Visual Studio Code, hovering over JSX elements (like input) can show you the inferred types. This is super helpful when you're building your own components or working with event handlers.
For example, hovering over an event handler like onClick will display the inferred type of the event parameter. This information helps ensure that your event handlers are correctly typed and can prevent potential runtime errors.
Union and Literal types
A union type allows a variable to hold a value that could be one of several specified types. It's defined using the pipe (|) operator.
Example:
type Direction = "up" | "down" | "left" | "right";
let move: Direction;
move = "up"; // ✅ Valid
move = "forward"; // ❌ Error
What about literal types?
Well, literal types represent specific, exact values rather than broad types. They can be strings, numbers, or booleans that have a fixed value.
let pet: "cat";
pet = "cat"; // ✅ Valid
pet = "dog"; // ❌ Error
Optional and readonly properties
Optional properties are those that may or may not be present in an object. They're defined using the ? syntax.
Example:
interface Person {
name: string;
age?: number;
}
const john: Person = { name: "John" }; // Valid
const jane: Person = { name: "Jane", age: 30 }; // Also valid
In this example, the age property is optional. This means that objects of type Person can either include or omit the age property. If omitted, age will be undefined.
And READONLY properties?
You can define readonly properties within object literals, ensuring that once a property is assigned a value, it cannot be modified.
interface Product {
readonly id: number;
name: string;
price: number;
}
const product: Product = {
id: 101,
name: "Laptop",
price: 999.99,
};
Attempting to modify the readonly property will result in a compile-time error
product.id = 102;
// Error: Cannot assign to 'id' because it is a read-only property.
Arrays and tuples
Arrays are ordered collections of elements that can hold multiple values of the same type:
let numbers: number[] = [1, 2, 3];
// or
type Person = {
numOfFingers: number[]
}
Tuples differ from arrays, because they're a collection of elements that can hold different types, but the number of elements is fixed.
let numbers: [number,number,number];
// or
type Person = {
typesOfFingers: [number, string]
}
Generic Types
Generics are a bigger topic by itself, so I'll add more information to it a bit later, but they act as placeholders for types.
When we don't know what type we're going to use and we don't want to use any, then it's a good use case for generics. Using any disables type safety so the compiler won't catch any mistakes, so in that case
it could be a good use case for generics.
An example:
function sports<T>(listOfSports : T[]) : T { return listOfSports[0]}
Typing props and state
This is how you'd normally type types for props and state:
type UserProps = {
name: string;
age?: number;
};
function UserCard({ name, age }: UserProps) {
return (
<div>
<h2>{name}</h2>
{age && <p>Age: {age}</p>}
</div>
);
}
// and for state:
function Counter() {
const [count, setCount] = useState<number>(0);
return (
<button onClick={() => setCount(count + 1)}> </button>
);
}
Typing hooks
We've already seen a short example as to how types look in useState hook, but what about others? Normally, you can also often find them out with useRef hook, but here's the thing: it differs a bit when it's meant for dom, and when it's meant just to hold a value.
import { useRef, useEffect } from 'react';
// an example for dom ref:
function InputFocus() {
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => {
inputRef.current?.focus();
}, []);
return <input ref={inputRef} />;
}
// an example for non dom ref:
function Counter() {
const [count, setCount] = useState(0);
const prevCountRef = useRef<number>(0);
useEffect(() => {
prevCountRef.current = count;
}, [count]);
return (
<div>
<p>Now: {count}</p>
<p>Before: {prevCountRef.current}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
Typing event handlers
There are countless examples, but these would be the most common one's:
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
console.log("Clicked", e);
};
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
console.log("Form submitted");
};
// you can easily find what type it should have by hovering on the element :)
Conclusion
Hope this clears things up a bit. I'll later add a few more examples, such as Records, Generics and such. :)