Array<Type> vs Type[] in TypeScript: The Syntax Battle You Must Win
\n\nIf you've ever written in TypeScript, you've definitely seen two ways to declare an array of numbers:
\n\nconst numbers1: number[] = [1, 2, 3];\nconst numbers2: Array<number> = [1, 2, 3];\n\nBoth options work. Both compile. Both are valid TypeScript. So why all the debate around them? Why does this question on Stack Overflow have thousands of views? And most importantly — how do you avoid the pitfalls that can break your project?
\n\nLet's figure it out once and for all. No boring theory. Only what you'll actually need in the trenches.
\n\nQuick Primer: What's What
\n\nType[] Syntax (Array Literal Syntax)
\n\nThis is the most common way to declare an array in TypeScript. It comes from JavaScript and looks natural:
\n\nlet fruits: string[] = ['apple', 'banana', 'cherry'];\nlet matrix: number[][] = [[1, 2], [3, 4]]; // Array of arrays\n\nShort, readable, intuitive. For 90% of cases, this is enough.
\n\nArray<Type> Syntax (Generic Syntax)
\n\nThis is the generic form, using the built-in Array<T> interface:
let fruits: Array<string> = ['apple', 'banana', 'cherry'];\nlet matrix: Array<Array<number>> = [[1, 2], [3, 4]];\n\nIt looks more "academic" but offers more flexibility in complex scenarios.
\n\nTop 5 Mistakes Even Experienced Developers Make
\n\nMistake #1: Blindly Trusting IDE Autocomplete
\n\nYour IDE might suggest both options. But that doesn't mean they are interchangeable everywhere. Consider an example with union types:
\n\n// This works\ntype Status = 'active' | 'inactive';\nconst statuses1: Status[] = ['active', 'inactive'];\n\n// But this — a syntax error!\n// const statuses2: Array<'active' | 'inactive'> = ['active', 'inactive']; \n// ❌ Error: ';' expected\n\n// Correct version with a generic:\nconst statuses3: Array<Status> = ['active', 'inactive'];\n\nConclusion: Inside Array<>, you cannot use complex union types directly. First, extract them into a separate type.
Mistake #2: Confusion with Readonly Arrays
\n\nWhen you need to make an array immutable, the syntaxes behave differently:
\n\n// ✅ Correct with Type[]\nconst readonlyFruits: readonly string[] = ['apple', 'banana'];\n// readonlyFruits.push('orange'); // ❌ Error: readonly\n\n// ❌ This won't work:\n// const wrong: readonly Array<string> = ['apple']; \n// Error: 'readonly' modifier can only appear on array types\n\n// ✅ Correct with Array<> — use ReadonlyArray:\nconst correct: ReadonlyArray<string> = ['apple', 'banana'];\n\nConclusion: For readonly arrays, use readonly Type[] or ReadonlyArray<Type>. You cannot mix readonly with Array<>.
Mistake #3: Problems with Multi-Level Arrays
\n\nWhen an array contains other arrays, the Array<> syntax becomes cumbersome:
// Readable and clear\nconst grid1: number[][] = [[1, 2], [3, 4]];\n\n// Already harder to read\nconst grid2: Array<Array<number>> = [[1, 2], [3, 4]];\n\n// And with three levels? A nightmare:\nconst cube: Array<Array<Array<number>>> = [[[1]]]; // 🤯\n\n// With Type[] it's much simpler:\nconst cube2: number[][][] = [[[1]]];\n\nConclusion: For arrays with more than 2 levels of nesting, use Type[][]. Your colleagues will thank you.
Mistake #4: Ignoring the Usage Context
\n\nIn some frameworks (Angular, React) and libraries, a specific style is adopted. Breaking the convention can cause confusion:
\n\n// Angular often u