TypeScript
Completed
-
Section 1: Getting Started
-
Section 2: Basic Types
-
Section 3: Functions and Objects
-
Section 4: Advanced Types
-
Section 5: Object-Oriented TypeScript
-
Section 6: Working with Modules
-
Section 7: Tooling and Practice
-
Section 8: Type-Level Programming
-
Section 9: TypeScript with Backends
-
Section 10: Testing Typed Code
-
Section 11: Data Validation with Types
-
Section 12: Practical Projects
-
Section 13: Compiler Internals
-
Section 14: Configuration Deep Dive
-
Section 15: Enums, Symbols, and Special Types
-
Section 16: Working with Async Code
-
Section 17: TypeScript and the DOM
-
Section 18: Advanced Generics Practice
-
Section 19: Working with Third-Party Types
-
Section 20: Monorepo and Large-Scale Practices
-
Section 21: Common Pitfalls and Best Practices
-
Section 22: Interview Practice
-
Section 23: Handbook: Narrowing In Depth
-
Section 24: Handbook: Object Types In Depth
-
Section 25: Handbook: Classes In Depth
-
Section 26: Handbook: Modules In Depth
-
Section 27: Handbook: Declaration Files In Depth
-
Section 28: JSX and Namespaces
-
Section 29: Compiler Configuration Reference
-
Section 30: More Practice Exercises
-
Section 31: Handbook: Everyday Types Deep Dive
-
Section 32: Utility Types Full Reference
-
Section 33: Decorators Reference
-
Section 34: Mixins and Advanced OOP Patterns
-
Section 35: Iterators and Generators Typing
-
Section 36: More Type-Level Programming Practice
-
Section 37: TypeScript Ecosystem Tools
-
Section 38: TypeScript with Testing Frameworks
-
Section 39: TypeScript for Library Authors
-
Section 40: More Interview Practice
-
Section 41: Handbook: Functions In Depth
-
Section 42: Handbook: Type Manipulation Deep Dive
-
Section 43: More Real-World Patterns
-
Section 44: TypeScript Release Notes Highlights
-
Section 45: Final Practice and Review
175: The Array Type Syntax T[] vs Array<T>
You’ve probably noticed that in TypeScript, there are two ways to tell the compiler you're dealing with a list of things. You can use the shorthand T[] syntax, or you can use the generic Array<T> syntax. If you look at the official documentation, they'll tell you they are functionally identical. The compiler doesn't care which one you pick; the resulting JavaScript is exactly the same.
But in a real-world codebase, consistency is everything. I often see developers—especially those coming from Java or C#—default to Array<T> because it feels more "explicit" and aligns with how they handle other generics like Maps or Sets. It looks like this:
type UserRole = 'admin' | 'editor' | 'viewer';
function assignPermissions(roles: Array<UserRole>) {
// logic here
}
Now, this isn't "wrong," but it is noisy. When I'm reviewing a pull request, my eyes have to parse those angle brackets every single time. Compare that to the shorthand:
function assignPermissions(roles: UserRole[]) {
// logic here
}
The visual tax of angle brackets
I always push my team toward T[]. Why? Because it's a quicker scan. When you're looking at a complex function signature with five or six arguments, string[] and number[] blend into the background, letting you focus on the actual logic. Array<string> draws more attention to the container than the content. Unless you have a very specific reason to use the generic syntax, the shorthand is the industry standard for a reason: it reduces cognitive load.
Where the shorthand gets tricky
There is one specific spot where the shorthand can trip you up, and it's usually where "naive" TypeScript starts to break. I'm talking about union types. Let's say you have a list that can contain either strings or numbers. If you write this:
const mixedData: string | number[] = ['hello', 1, 2];
You've just created a bug. You didn't tell TypeScript you have an array of strings-or-numbers; you told it that the variable mixedData is either a single string OR an array of numbers. The compiler will scream at you the moment you try to treat mixedData as an array because it might just be a string.
To fix this with shorthand, you have to wrap the union in parentheses: (string | number)[]. At this point, I'll admit that Array<string | number> actually looks a bit cleaner. The angle brackets act as natural boundaries, making it obvious that the union is the type being stored in the array. I occasionally use the generic syntax for these complex types just to avoid the "parentheses soup," but for 95% of your arrays, T[] is the way to go.
Choosing your baseline
My advice is to pick a baseline and stick to it. Mixing string[] and Array<string> in the same file is a sign of a codebase that hasn't been curated. If you're working on a project that already uses Array<T>, follow the existing pattern. But if you're starting fresh, go with T[]. It's leaner, faster to read, and it's what most of the TypeScript ecosystem expects to see.
📋 Practical Task
Refactoring the Project Access Control List
You've inherited a module for managing project permissions. The current code is inconsistently typed and contains a logic error where a union type array was declared incorrectly, causing the compiler to think the variable is a single string rather than a list of identifiers.
Your Task: Refactor the following code to use the T[] shorthand consistently throughout. Then, fix the authorizedIds type declaration so that it correctly represents an array that can hold either strings or numbers.
type Identifier = string | number;
type Permission = 'read' | 'write' | 'execute';
interface ProjectConfig {
projectName: string;
// FIX THIS: This is currently typed as "a string OR an array of numbers"
authorizedIds: Identifier | number[];
// REFACTOR THIS: Use the shorthand syntax
permissions: Array<Permission>;
}
function validateAccess(config: ProjectConfig, userIds: Array<Identifier>): boolean {
return config.authorizedIds.includes(userIds[0]);
}There are no comments for now.