How to TypeScript for React Developers: A Comprehensive Guide (Part 1)
By: Otlyn Black
Over the past few years, TypeScript has grown from a niche tool into a cornerstone of modern web development. In this series, we’ll explore its impact on React development and how it can elevate your codebase. TypeScript brings powerful advantages like type safety, improved refactoring, and intelligent tooling — all of which contribute to a smoother, more reliable development experience.
This guide is for React developers of all levels — no prior TypeScript experience needed. In Part 1, we’ll focus on the fundamentals of the TypeScript language, with React development in mind. By building a strong foundation, integrating TypeScript into your React projects will feel like a natural next step rather than a hurdle.
A little about me: I’m Otlyn Black — a functional programmer and Principal Software Engineer at Volvo Group. I’ve been working with TypeScript for several years now and have seen firsthand how powerful it can be when paired with React. Let’s dive in!
TypeScript Playground
No installs, no configs — just open your browser to TypeScript Playground and you’re in! Start writing, transpiling, and sharing TypeScript instantly — let’s get coding.
The code terminal should look something like this:
// Welcome to the TypeScript Playground, this is a website
// which gives you a chance to write, share and learn TypeScript.
// You could think of it in three ways:
//
// - A location to learn TypeScript where nothing can break
// - A place to experiment with TypeScript syntax, and share the URLs with others
// - A sandbox to experiment with different compiler features of TypeScript
const anExampleVariable = "Hello World"
console.log(anExampleVariable)
// To learn more about the language, click above in "Examples" or "What's New".
// Otherwise, get started by removing these comments and the world is your playground.Go ahead — delete all the existing code so we can start fresh.
Type Safety
With a blank canvas in front of you, let’s start with TypeScript’s biggest feature: type safety! TypeScript automatically infers types from the values you assign.
For example:
let fullName = "Otlyn Black";Here, TypeScript infers that fullName is a string. So if you try to reassign it like this:
let fullName = "Otlyn Black";
fullName = 123; // ❌ Type 'number' is not assignable to type 'string'TypeScript will throw an error. Go ahead, give it a try.
This kind of early error detection is a huge part of what makes TypeScript so powerful for writing safe, maintainable code.
Explicit Type Annotations
TypeScript is great at inferring types, but sometimes it’s necessary to be explicit, especially with complex types like objects, arrays, or functions. For now, let’s focus on using explicit types for clarity and readability.
Here’s how you can explicitly type a variable:
let fullName: string;
let age: number;
let isHungry: boolean;
let rhymesWithToll: null;
let lifeGoals: undefined;If you try to assign a value that doesn’t match the declared type, TypeScript will throw an error.
Hover over the variable to see the TypeScript error:
fullName = true; // ❌ Type 'boolean' is not assignable to type 'string'
age = "old"; // ❌ Type 'string' is not assignable to type 'number'
isHungry = Infinity; // ❌ Type 'number' is not assignable to type 'boolean'
rhymesWithToll = "belly"; // ❌ Type 'string' is not assignable to type 'null'
lifeGoals = 123; // ❌ Type 'number' is not assignable to type 'undefined'Just like in JavaScript, you’ll use these primitive types all the time. But what if you need a variable that can hold more than one type? Let’s dive into union types and see how to do just that.
Union Types
Don’t be intimidated by the name. A union type is just a way to allow a variable to accept more than one type. Think of it as a “union” that brings different types together.
For example:
let id: string;
id = "abc";
id = 123; // ❌ Type 'number' is not assignable to type 'string'To allow both string and number, you can create a union type:
let id: string | number;
id = "abc";
id = 123; // ✅ Works as expected!Union types are great when a variable needs to hold one of several types — but what if you want to store many values at once? That’s where arrays come in.
Array Types
Arrays in TypeScript are simple — just add brackets after the type! For example, here’s how to define an array of strings:
let strArr: string[];
strArr = ["foo", "bar", "baz"];You can use the same syntax for other types too:
let numArr: number[];
numArr = [1, 2, 3];
let boolArr: boolean[];
boolArr = [true, false, true];
let nullArr: null[];
nullArr = [null, null, null];Okay, an array of nulls isn’t super useful… let’s look at something a bit more practical.
Arrays with Multiple Types
Remember union types from earlier? You can use them with arrays too! Just be sure to include the parentheses — they’re important for grouping:
let mixedArr: (string | number | boolean)[];
mixedArr = [1, "foo", true]; // ✅ Works perfectly!Without the parentheses, TypeScript will get confused and think you want a union of arrays instead of an array of unions.
Array Types using Generic Syntax
Alternatively, you can write array types using a more general syntax:
let mixedArrAlt: Array<string | number | boolean>; // ✅ Also works!
mixedArrAlt = [1, "foo", true]; // ✅ Still perfect!Both (string | number)[] and Array<string | number> are exactly the same under the hood.
We’ll dig deeper into generics and why they matter in Part 2. For now, here’s a quick look at how all the previous examples look using the generic syntax instead:
let strArr: Array<string>;
strArr = ["foo", "bar", "baz"];
let numArr: Array<number>;
numArr = [1, 2, 3];
let boolArr: Array<boolean>;
boolArr = [true, false, true];
let nullArr: Array<null>;
nullArr = [null, null, null];
let mixedArr: Array<string | number | boolean>;
mixedArr = [1, "foo", true];Same behavior — just a different flavor! Use whichever syntax feels more readable to you.
Object Types
So we’ve got arrays down — great for lists, tuples, and anything that comes in multiples. But what if you need something a little more… structured.
That’s right — it’s time for objects.
let user: { id: number; name: string; age: number; isHungry: boolean };
user = {
id: 1,
name: "Otlyn Black",
age: 34,
isHungry: true,
};Up to this point, we’ve been defining all our types inline, which is totally valid (and often preferred for quick, simple cases). However, once things scale, it’s time for something a little tidier.
Custom Types
Let’s clean it up by creating a reusable custom type. Take note that types should be written in PascalCase (e.g., FooBarBaz, CustomerService, UserProfile):
type User = {
id: number;
name: string;
age: number;
isHungry: boolean;
};Now instead of cramming the type into your variable, just reference it by name:
let user: User;TypeScript will now make sure user matches the shape you defined. Easy!
user = {
id: 1,
name: "Otlyn Black",
age: 40,
isHungry: true,
};And if something’s off, TypeScript lets you know:
user = {
id: "123", // ❌ Nope—should be a number.
name: true, // ❌ Also nope—should be a string.
age: "old", // ❌ Not quite—should be a number.
isHungry: 100, // ❌ That's not a boolean.
};You can also get fancy — like allowing multiple types with unions:
type User = {
id: number | string; // ✅ Now id can be either
name: string;
age: number;
isHungry: boolean;
};
let user: User;
user = {
id: "abc", // ✅ See, it works!
name: "Otlyn Black",
age: 40,
isHungry: true,
};Custom types help keep your code reusable, maintainable, and way cleaner as your app grows.
Let’s Apply What We’ve Learned
You’ve made it this far? Heck yes! I’m genuinely impressed. Before we jump into the final stretch (functions!), let’s take a breather and apply everything we’ve learned so far.
Up to now, we’ve been writing our type declarations and assignments on separate lines, like this:
let fullName: string;
fullName = "Otlyn Black";Totally valid. But there’s a shortcut that not only saves keystrokes — it also becomes super handy when we start working with functions.
Check this out:
let fullName: string = "Otlyn Black";Same thing, just cleaner. This pattern is really common, and you’ll see it a lot — especially when we start working with React components in Part 2.
Now that you’ve got the hang of that, let’s update our earlier examples using custom types and this slick one-liner style. Since we won’t be reassigning these variables, we’ll convert them to constants:
type FullName = string;
type Age = number;
type IsHungry = boolean;
type RhymesWithToll = null;
type LifeGoals = undefined;
const fullName: FullName = "Otlyn Black";
const age: Age = Infinity;
const isHungry: IsHungry = true;
const rhymesWithToll: RhymesWithToll = null;
const lifeGoals: LifeGoals = undefined;Looking sharp. Let’s do the same for arrays:
type StringArray = string[];
type NumberArray = number[];
type BooleanArray = boolean[];
type NullArray = null[];
type MixedArray = (string | number | boolean)[];
const strArr: StringArray = ["foo", "bar", "baz"];
const numArr: NumberArray = [1, 2, 3];
const boolArr: BooleanArray = [true, false, true];
const nullArr: NullArray = [null, null, null];
const mixedArr: MixedArray = [1, true, "Answer"];Nice work. Clean types, clear values, and now you’ve got a style that’ll make things way easier to read and write — especially as we dive into…
🥁 Functions!
Function Types
Just like with variables, function types in TypeScript are all about describing what goes in (parameters) and what comes out (the return value).
Let’s start with a plain JavaScript function:
const add = (a, b) => a + b;This works, but TypeScript warns us parameter a and b implicitly have an any type. That’s not what we want. Add parameter types like this:
const add = (a: number, b: number) => a + b;Nice! TypeScript can now infer that the return value will also be a number. But to be extra clear (and get in some good practice), let’s be explicit:
const add = (a: number, b: number): number => a + b;That : number after the parameters locks in the return type. Now TypeScript knows exactly what this function is supposed to return.
Custom Function Types
Remember that one-liner pattern we used earlier — where we defined the type and used it in the same breath? We can do the exact same thing for functions using a custom type!
Let’s define a custom function type like this:
type Calculation = (a: number, b: number) => number;Now we can use that Calculation type anywhere we need a function that takes two numbers and returns a number:
const add: Calculation = (a, b) => a + b;
const subtract: Calculation = (a, b) => a - b;
const multiply: Calculation = (a, b) => a * b;
const divide: Calculation = (a, b) => a / b;Clean, reusable, and easy on the eyes. You’ll use this pattern a lot — especially in React, where typed props, handlers, and logic are key.
And speaking of React…
You’ve just completed Part 1 of How to TypeScript for React Developers: A Comprehensive Guide!
Congrats — you’re officially smarter than you were a few minutes ago. 🎉
Summary
In Part 1, we laid the foundation by exploring TypeScript’s core building blocks:
- Type Safety
- Implicit type inference
- Explicit type definitions
- Primitive types
- Union types (remember those mixed types!)
- Custom types
- TypeScript syntax
- And more…
Next up…
In Part 2, we’ll dive into the fun stuff: creating a React + TypeScript project, integrating TypeScript into your IDE, and learning how to type props, state, user inputs, events, and much more. We’ll explore function types in depth and go from simple components to confidently building maintainable, type-safe UIs. Stay tuned — it’s going to be a blast!
Bio: Otlyn Black
I’m a functional programmer and Principal Software Engineer at Volvo Group Connected Solutions. When I’m not at the keyboard, I’m canoeing through nature, making new friends, traveling, spending time with family, or eating chocolate chip cookies in excess. These days, I’m living my best life in Sweden with my wife, Olya — bring on the summer sun!
Enjoyed this article? Follow us to be notified when Parts 2 and 3 of this series go live. Thanks for your time!
