Hands‑On Exercise: Type a Small Array Utility Library¶
In this exercise, you’ll take a small JavaScript “array helpers” module and progressively add TypeScript types to make it safer, clearer, and more maintainable.
The goal is to show how TypeScript transforms everyday JavaScript into a robust, self‑documenting API.
Step 1 — Start with a plain JavaScript utility file¶
Create a file named arrayUtils.js:
// arrayUtils.js
export function first(arr) {
return arr[0]
}
export function last(arr) {
return arr[arr.length - 1]
}
export function findById(arr, id) {
return arr.find(item => item.id === id)
}
export function chunk(arr, size) {
const result = []
for (let i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, i + size))
}
return result
}
This works in JavaScript, but it has problems:
- No guarantee that
arris an array - No guarantee that items have an
id chunkreturns arrays of arrays, but nothing enforces that- No autocomplete or IntelliSense for consumers
Now let’s convert it to TypeScript.
Step 2 — Rename the file to TypeScript¶
arrayUtils.js → arrayUtils.ts
Immediately, TypeScript will start complaining—good!
This is where the learning happens.
Step 3 — Add parameter and return types¶
Start by typing the simplest functions.
first and last¶
export function first<T>(arr: T[]): T | undefined {
return arr[0]
}
export function last<T>(arr: T[]): T | undefined {
return arr[arr.length - 1]
}
Concepts used:
- Generic type parameter
<T> - Typed arrays (
T[]) - Union return type (
T | undefined)
In the code above we introduced generics. We haven’t talked about generics yet, and we will introduce them in a separate lesson. For now, consider them as generic type placeholders. In the example above,
first<T>(arr: T[])takes an array of typeTand returns: T | undefined, a value of typeTorundefined.
Step 4 — Type the findById function¶
We want to enforce that:
arris an array of objects- each object has an
idproperty idcan be a string or number
export function findById<T extends { id: string | number }>(
arr: T[],
id: string | number
): T | undefined {
return arr.find(item => item.id === id)
}
Concepts used:
- Type constraint (
T extends { id: ... }) (once again, this will be covered in the coming lessons) - Typed arrays
- Union types
Step 5 — Type the chunk function¶
chunk returns an array of arrays, so we use generics again.
export function chunk<T>(arr: T[], size: number): T[][] {
const result: T[][] = []
for (let i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, i + size))
}
return result
}
Concepts used:
- Nested arrays (
T[][]) - Explicit return type
- Typed intermediate variables
Step 6 — Add a tuple‑based helper (optional bonus)¶
Let’s add a helper that returns both the min and max of a numeric array.
export function minMax(arr: number[]): [min: number, max: number] {
const min = Math.min(...arr)
const max = Math.max(...arr)
return [min, max]
}
Concepts used:
- Tuples
- Named tuple elements
Step 7 — Test the library¶
Create a file test.ts:
import { first, last, findById, chunk, minMax } from "./arrayUtils"
const nums = [10, 20, 30]
first(nums) // number | undefined
last(nums) // number | undefined
chunk(nums, 2) // number[][]
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" }
]
findById(users, 2) // { id: number; name: string } | undefined
minMax(nums) // [number, number]
Hover over each function call in your editor—you’ll see TypeScript’s type inference in action.
Step 8 — Observe compiler feedback¶
Try breaking things intentionally:
first("not an array") // ❌ Error
findById(users, true) // ❌ Error
chunk(nums, "two") // ❌ Error
minMax(["a", "b"]) // ❌ Error
TypeScript catches all of these mistakes before runtime.
What You Learned¶
This exercise demonstrates how TypeScript transforms a simple utility library into a safe, expressive API.
Concepts applied:¶
- Generic functions
- Typed arrays
- Tuple return types
- Type constraints
- Union types
- Explicit return types
- Compiler‑driven feedback
Benefits gained:¶
- Safer code
- Better autocomplete
- Clearer API contracts
- Fewer runtime bugs
- Easier refactoring
This is exactly how TypeScript improves real‑world JavaScript codebases.