LearnFrenzy
Sign in Take a free test

TypeScript Basic Types · Lesson 3 of 17

TypeScript Types: Primitives, Arrays and Tuples

4 min read Updated Nov 8, 2026 Saurabh Samir

Every value in TypeScript has a type, but you rarely need to write it: TypeScript infers types from the values you assign. This lesson covers the everyday types – primitives, arrays and tuples – and the professional habit of annotating where it helps and letting inference do the rest.

In this lesson

  • Primitive types and annotations
  • Type inference: when to annotate
  • Arrays and readonly arrays
  • Tuples

Primitive types

let course: string = "TypeScript";
let lessons: number = 20;               // one number type for integers and decimals
let published: boolean = true;
let views: bigint = 9_007_199_254_740_993n;
let nothing: null = null;
let notSet: undefined = undefined;

lessons += 2;
console.log(course, lessons, published, views, nothing, notSet);
console.log(typeof course, typeof lessons, typeof views);

Output

TypeScript 22 true 9007199254740993n null undefined
string number bigint

Use the lowercase names (string, number, boolean). String and Number with capitals are JavaScript wrapper objects – almost never what you want in a type.

Type inference

let city = "Pune";                        // inferred: string
const country = "India";                  // inferred: the literal type "India" (it can't change)
let marks = [78, 91, 64];                 // inferred: number[]
let mixed = [1, "two", true];             // inferred: (string | number | boolean)[]

city = "Delhi";                           // fine
city = 42;                                // error: number is not a string
marks.push("85");                         // error: string is not a number
console.log(city, country, marks, mixed);

Type errors

main.ts(7,1): error TS2322: Type 'number' is not assignable to type 'string'.
main.ts(8,12): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

When to write types

  • Do annotate function parameters – TypeScript can't guess them.
  • Do annotate return types of exported functions and public APIs – it documents and protects the contract.
  • Do annotate empty arrays and variables declared without a value: const ids: number[] = [];
  • Don't annotate obvious locals: let count: number = 0 adds noise.

Arrays

const scores: number[] = [72, 95, 41, 88];
const names: Array<string> = ["Asha", "Ravi"];       // same as string[]
const matrix: number[][] = [[1, 2], [3, 4]];

const passed = scores.filter((s) => s >= 50);        // number[] inferred from the callback
const labels = scores.map((s) => `${s}%`);            // string[]
console.log(passed, labels, matrix[1], names.length);

const days: readonly string[] = ["Mon", "Tue", "Wed"];
console.log(days.length, days.includes("Tue"));
// days.push("Thu");      // error: Property 'push' does not exist on type 'readonly string[]'

Output

[ 72, 95, 88 ] [ '72%', '95%', '41%', '88%' ] [ 3, 4 ] 2
3 true

readonly arrays (also written ReadonlyArray<string>) remove every mutating method at compile time – ideal for function parameters that shouldn't change their input.

Index access and noUncheckedIndexedAccess

const top3: number[] = [99, 92, 88];
const fourth = top3[3];                     // number at compile time… undefined at run time
console.log(fourth, typeof fourth);

Output

undefined undefined

By default TypeScript types top3[3] as number, though it's undefined. With "noUncheckedIndexedAccess": true (recommended in the previous lesson) it becomes number | undefined, forcing you to check.

Tuples

A tuple is an array with a fixed length and a known type at each position:

const point: [number, number] = [3, 4];
const entry: [string, number] = ["Asha", 91];
const [name, score] = entry;                         // destructuring keeps the types

function minMax(values: readonly number[]): [min: number, max: number] {   // labelled tuple
  return [Math.min(...values), Math.max(...values)];
}
const [lo, hi] = minMax([42, 7, 93, 18]);

const httpStatus: [code: number, text: string, retry?: boolean] = [503, "Service Unavailable"];
console.log(point, name, score, lo, hi, httpStatus.length);

Output

[ 3, 4 ] Asha 91 7 93 2

React's useState returns a tuple: const [count, setCount] = useState(0) – the first element is the value, the second the setter, each with its own type.

Practice

Try it yourself

  1. Write average(values: readonly number[]): number and a tuple-returning split(name: string): [first: string, last: string].

    Show solution
    function average(values: readonly number[]): number {
      return values.length === 0 ? 0 : values.reduce((a, b) => a + b, 0) / values.length;
    }
    function split(name: string): [first: string, last: string] {
      const [first = "", ...rest] = name.split(" ");
      return [first, rest.join(" ")];
    }
    console.log(average([70, 85, 90]).toFixed(2), split("Asha Verma"));

    Output

    81.67 [ 'Asha', 'Verma' ]

Quick check

What type does let x = [1, 2] get?

number[].

Where should you always write types?

Function parameters (and usually exported return types).

Array vs tuple?

An array has any length of one element type; a tuple has a fixed length with a type per position.

Summary

  • Primitive types: string, number, boolean, bigint, null, undefined (lowercase).
  • Inference handles most locals; annotate parameters, public returns and empty values.
  • T[] arrays, readonly T[] for read-only data, and [A, B] tuples for fixed positions.

Finished this lesson?

Mark it complete to track your progress, then carry on with the next lesson.

Next lesson

Search LearnFrenzy

Esc

Quick links