Understanding TypeScript Types: A Comprehensive Guide
/ 4 min read
Understanding TypeScript Types
TypeScript’s type system is one of its most powerful features, providing enhanced code quality, better tooling support, and improved developer experience. This comprehensive guide will walk you through everything you need to know about TypeScript types.
Table of Contents
Introduction to Types
TypeScript’s type system adds an extra layer of safety and developer productivity to JavaScript. Types help catch errors early in development, provide better documentation, and enable powerful IDE features like autocomplete and refactoring.
Primitive Types
TypeScript includes all JavaScript primitive types and adds a few additional ones:
// Numberlet age: number = 25;let price: number = 99.99;
// Stringlet name: string = "John";let greeting: string = `Hello ${name}`;
// Booleanlet isActive: boolean = true;
// Null and Undefinedlet nullValue: null = null;let undefinedValue: undefined = undefined;
// Symbollet sym: symbol = Symbol("key");
// BigIntlet bigNumber: bigint = 100n;Complex Types
Arrays
// Array of numberslet numbers: number[] = [1, 2, 3];let numbers2: Array<number> = [1, 2, 3]; // Generic array type
// Array of mixed typeslet mixed: (string | number)[] = ["hello", 1, "world"];Tuples
// Fixed-length array where each element has a specific typelet tuple: [string, number] = ["hello", 42];
// Optional elementslet optionalTuple: [string, number?] = ["hello"];Objects
// Object type annotationlet user: { name: string; age: number; email?: string; // Optional property} = { name: "John", age: 30};
// Index signatureslet dictionary: { [key: string]: number } = { "one": 1, "two": 2};Type Annotations and Inference
TypeScript can often infer types automatically:
// Type inferencelet inferredString = "hello"; // Type: stringlet inferredNumber = 42; // Type: number
// Explicit type annotationslet explicitString: string = "hello";let explicitNumber: number = 42;
// Function type annotationsfunction add(a: number, b: number): number { return a + b;}Literal Types
Literal types allow you to specify exact values:
// String literal typeslet direction: "north" | "south" | "east" | "west";direction = "north"; // Valid// direction = "northeast"; // Error!
// Numeric literal typeslet diceRoll: 1 | 2 | 3 | 4 | 5 | 6;diceRoll = 1; // Valid// diceRoll = 7; // Error!
// Boolean literal typelet status: true;status = true; // Valid// status = false; // Error!Union and Intersection Types
Union Types
// Union typetype StringOrNumber = string | number;let value: StringOrNumber = "hello";value = 42; // Also valid
// Union with literal typestype Status = "pending" | "approved" | "rejected";let currentStatus: Status = "pending";Intersection Types
type HasName = { name: string };type HasAge = { age: number };
// Intersection typetype Person = HasName & HasAge;
let person: Person = { name: "John", age: 30};Type Assertions
Type assertions allow you to tell TypeScript that you know better about the type of a value:
// Using angle-bracket syntaxlet someValue: any = "this is a string";let strLength: number = (<string>someValue).length;
// Using 'as' syntax (preferred in JSX)let someValue2: any = "this is a string";let strLength2: number = (someValue2 as string).length;
// Non-null assertionlet nullableString: string | null = "hello";let definiteString: string = nullableString!; // Assert value is non-nullBest Practices
- Use Type Inference When Possible
// Goodlet message = "Hello"; // Type inference works well here
// Less ideal (unnecessary annotation)let message: string = "Hello";- Be Specific with Types
// Bettertype UserStatus = "active" | "inactive" | "pending";let status: UserStatus = "active";
// Less ideallet status: string = "active";- Avoid
anyType
// Avoidfunction processData(data: any) { // ...}
// Betterfunction processData<T>(data: T) { // ...}- Use Type Guards for Runtime Safety
function processValue(value: string | number) { if (typeof value === "string") { // TypeScript knows value is a string here console.log(value.toUpperCase()); } else { // TypeScript knows value is a number here console.log(value.toFixed(2)); }}Conclusion
Understanding TypeScript types is fundamental to writing better, safer code. They provide compile-time safety, better documentation, and improved developer experience. Remember to:
- Use types to catch errors early in development
- Leverage type inference when possible
- Be specific with your types
- Use union and intersection types for flexibility
- Apply type assertions judiciously
- Follow TypeScript best practices
TypeScript’s type system is extensive and powerful. As you become more comfortable with these basics, you can explore more advanced type features like conditional types, mapped types, and utility types.