A TypeScript array type is the element type followed by []: string[] is an array of strings, number[] an array of numbers. The generic spelling Array<string> is the same type. Once an array is typed, every element you add and every element you read has that type.
The @ts-expect-error line is a compile error (TS2345). Here it is marked as expected so the block still runs, and since types are erased, the 42 really is pushed at runtime: the output shows it.
string[] vs Array<string>
| Written as | Same as | Notes |
|---|---|---|
string[] | Array<string> | The common spelling. |
(string | number)[] | Array<string | number> | Parentheses are required: string | number[] means "a string, or an array of numbers". |
readonly string[] | ReadonlyArray<string> | No push, pop, sort or index assignment. |
User[] | Array<User> | Arrays of objects use the object's type. |
string[][] | Array<Array<string>> | A 2D array (grid). |
Pick one style for a codebase. typescript-eslint's array-type rule defaults to T[].
Arrays of Objects
Describe the element with a type alias or interface, then use Type[]. Everything read out of the array is checked against that shape.
An object literal pushed into users must match User exactly: a missing admin or a misspelled property is a compile error.
Typed map, filter, reduce and find
The array methods are generic, so their results carry types. What each method does at runtime is covered on the JavaScript array methods page; the types are what TypeScript adds:
| Method | Result type on T[] |
|---|---|
map(fn) | U[], where U is what fn returns |
filter(fn) | T[] (or a narrower type, see below) |
find(fn) | T | undefined |
findIndex(fn), indexOf(x) | number (-1 if absent) |
some(fn), every(fn), includes(x) | boolean |
reduce(fn, init) | the type of init (or the type argument, reduce<R>(...)) |
at(i) | T | undefined |
join(sep) | string |
The last example works because TypeScript (since 5.5) infers that (n) => n !== undefined is a type predicate, so filter returns number[] rather than (number | undefined)[]. For checks it cannot infer, write the predicate yourself: filter((x): x is User => x !== null).
Arrays That Hold More Than One Type
A union element type allows a mix. A union of array types does not:
When positions have fixed types, like a [name, age] pair, use a tuple instead: [string, number] knows that index 0 is a string and index 1 is a number, where (string | number)[] does not.
Readonly Arrays
readonly T[] removes every method that mutates the array. Use it for parameters a function should not change, and for constants.
index.ts(3,12): error TS2339: Property 'push' does not exist on type 'readonly number[]'.
Delete the push line and the block prints 4. A mutable number[] can always be passed where readonly number[] is expected, so readonly parameters cost callers nothing. The check is compile-time only: at runtime it is an ordinary array. To sort a readonly array, sort a copy: [...values].sort().
The includes Pitfall with Literal Arrays
as const turns an array into a readonly tuple of literal types. That is useful for a list of allowed values, but its includes then only accepts those literals:
Wrapping the check in a type guard (value is Color) means the widening happens once, and callers get a narrowed value back.
Indexing and Empty Arrays
Reading arr[i] gives type T, even when i is out of range and the runtime value is undefined. at(i) is typed T | undefined, and the compiler option noUncheckedIndexedAccess makes plain indexing return T | undefined too.
queue[0].toUpperCase() would compile and then throw a TypeError at runtime. Prefer at(), a length check, or noUncheckedIndexedAccess when an index may be missing.
Frequently Asked Questions
How do you declare an array type in TypeScript?
Write the element type followed by []: let names: string[] = ["a", "b"]. The generic form Array<string> means exactly the same thing. For an array of objects, use an object type or interface as the element type: User[].
What is the difference between string[] and Array<string>?
None: they are two spellings of the same type. string[] is more common. The generic form reads better for complex element types, and for readonly arrays readonly string[] and ReadonlyArray<string> are likewise the same.
Why does find return undefined in TypeScript?
array.find() returns T | undefined because nothing may match. Under strict you must handle the undefined case, with an if check, optional chaining (found?.name) or a default (found ?? fallback), before using the result.
How do I type an array with multiple types in TypeScript?
Use a union element type in parentheses: (string | number)[] is an array where each element is a string or a number. That is different from string[] | number[], which is either an array of only strings or an array of only numbers. For a fixed order of types, such as [string, number], use a tuple.
Why does includes give an error on an as const array?
as const array?A readonly array of literals, such as ["red", "green"] as const, has includes(searchElement: "red" | "green"), so passing a plain string is error TS2345. Widen the array for the check, (COLORS as readonly string[]).includes(input), ideally inside a type guard that narrows input to the literal union.