Overview of TypeScript Type System and Core Features
1. Common Type Annotations
Basic type annotation syntax example:
let userAge: number = 24;
Existing Types Inherited from JavaScript
- Primitive types:
number,string,boolean,null,undefined,symbol - Object types:
object(includes arrays, plain objects, functions and other object values)
New Types Introduced by TypeScript
Union types, type aliases, interfaces, tuples, literal types, enums, void, any and more.
Key Difference Between Type Alias and Interface
- Type aliases can define constraints for any data type
- Interfaces can only define constraints for object types
Common type usage examples:
// Two ways to write array types
let testScores: number[] = [92, 85, 77, 98]; // Recommended approach
let fruitList: Array<string> = ['apple', 'banana', 'orange', 'grape'];
// Union type usage
let userId: number | string = 'user_8a7d6f';
let entryValue: number | string[] = 404; // Either a number or a string array
let mixedCollection: (number | string)[] = [200, 'request success', 404, 'not found']; // Array with both number and string values
// Type alias
type MixedNumStrArray = (number | string)[];
let orderRecords: MixedNumStrArray = [1001, 'wireless headphone', 1002, 'bluetooth speaker'];
// Function type annotation
function calculateDouble(input: number): number {
return input * 2;
}
// Optional function parameter, void return type
function printLog(message?: string): void {
console.log(message || 'No log content provided');
}
// Object type annotation
let customer: {
fullName: string;
age: number;
sendGreeting(): void
} = {
fullName: 'Luna Garcia',
age: 28,
sendGreeting() {}
};
// Interface definition
interface PlatformUser {
username: string;
age: number;
}
let registeredUser: PlatformUser = { username: 'luna01', age: 28 };
// Interface inheritance
interface Point2D { x: number; y: number }
interface Point3D extends Point2D { z: number }
// Tuple type
let geoCoordinates: [number, number] = [39.9042, 116.4074];
// Type inference
let postCount = 10; // Automatically inferred as number type
let unassignedVar; // No inferred type, defaults to any
unassignedVar = 5;
// Literal type
const adminRole = "super_admin"; // Const-declared constant has literal type "super_admin"
let allowedRole: "admin" | "editor" | "viewer" = "editor"; // Only allows 3 specified string values
// Enumeration (enum) type
enum UserRole { SuperAdmin, Editor, Viewer }
let currentUserRole: UserRole = UserRole.Editor;
// Default numeric enum increments from 0, output: 0 1 2
console.log(UserRole.SuperAdmin, UserRole.Editor, UserRole.Viewer);
// Custom starting value for numeric enum
enum StatusCode { Ok = 200, Created, BadRequest = 400, NotFound }
// StatusCode.Ok=200, StatusCode.Created=201, StatusCode.NotFound=401
// String enum requires explicit initial value for all members
enum NotificationType { Success = "SUCCESS", Error = "ERROR", Warning = "WARNING" }
// any type (bypasses all type checks)
let arbitraryValue: any = { count: 0 };
arbitraryValue(); // No type error
arbitraryValue.nonExistentProperty = 10; // No type error
// typeof operator in TypeScript
let referencePoint = { x: 15, y: 25 };
// Equivalent to (point: { x: number; y: number }) => void
function drawPoint(point: typeof referencePoint) {
// Drawing logic
}
2. Advanced Type Annotations
Advanced type features include:
- Class type system
- Type compatibility
- Intersection types
- Generics and
keyofoperator - Endex signature types, index query types
- Mapping types
2.1 Class Type
Basic class usage example:
class Product {
basePrice = 99;
}
const laptop = new Product();
// laptop is inferred as Product type, laptop.basePrice is number type
console.log(laptop.basePrice);
Class with constructor and instance methods:
class Product {
basePrice: number;
category: string;
constructor(basePrice: number, category: string) {
this.basePrice = basePrice;
this.category = category;
}
adjustPrice(increment: number): void {
this.basePrice += increment;
}
}
const smartphone = new Product(699, 'electronics');
smartphone.adjustPrice(50);
// smartphone.basePrice becomes 749
2.2 Class Inheritance and Interface Implementation
Class Inheritance (extends keyword)
class Creature {
move(): void {
console.log('Moving along the path');
}
}
class Cat extends Creature {
meow(): void {
console.log('Meow~');
}
}
const strayCat = new Cat();
strayCat.move(); // Inherited from parent class
strayCat.meow(); // Own method
Interface Implementation (implements keyword)
// Step 1: Define interface constraint
interface Playable {
play(): void;
}
// Step 2: Class implements interface, must implement all methods defined in interface
class MusicTrack implements Playable {
play(): void {
console.log('Playing audio track');
}
}
2.3 Access Modifiers: public / protected / private
public: Accessible anywhere (default modifier)protected: Accessible only inside the class and its subclasses, not accessible from class instancesprivate: Accesisble only inside the class itself
2.4 readonly Modifier
class Employee {
// Explicit type annotation is required, otherwise type will be inferred as literal 1000
readonly employeeId: number = 1000;
constructor(employeeId: number) {
// Can modify readonly property only inside constructor
this.employeeId = employeeId;
}
}
const staffMember = new Employee(1024);
console.log(staffMember.employeeId); // Allowed to read
staffMember.employeeId = 2048; // Type error, cannot modify readonly property outside constructor
2.5 Type Compatibility
[Note: Original type compatibility comparison diagrams are not available, this section is omitted for clarity.]
2.6 Intersection Types
Combine multiple type constraints into one:
interface Customer { fullName: string }
interface ContactInfo { phoneNumber: string }
// CustomerProfile has all properties from both Customer and ContactInfo
type CustomerProfile = Customer & ContactInfo;
2.7 Generics
Generic Function
// <Type> is a generic type placeholder
function identity<Type>(inputValue: Type): Type {
return inputValue;
}
// Explicitly specify generic type
const numberResult = identity<number>(123);
// Generic type can be omitted thanks to type inference
const stringResult = identity('test string content');
Generic Constraints
// Constraint that input must be an array of generic type
function getArrayLength<Type>(inputArray: Type[]): number {
return inputArray.length;
}
// Use extends to add custom generic constraint
interface LengthAvailable { length: number }
function logInputLength<Type extends LengthAvailable>(input: Type): void {
// Input is guaranteed to have length property, no type error
console.log(input.length);
}
keyof Operator
// Constraint that key must be a valid property of the input object
function getProperty<ObjType, Key extends keyof ObjType>(obj: ObjType, key: Key) {
return obj[key];
}
getProperty({ bookTitle: 'TypeScript Guide', pageCount: 320 }, 'bookTitle');
getProperty({ bookTitle: 'TypeScript Guide', pageCount: 320 }, 'pageCount');
Ganeric Interface
interface CrudService<DataType> {
getById: (id: number) => DataType;
getAll: () => DataType[];
}
// Implement generic interface with specified type
const userService: CrudService<PlatformUser> = {
getById(id) {
return { username: 'test_user', age: 26 };
},
getAll() {
return [];
}
};
2.8 Generic Utility Types
Common built-in generic utility types:
Partial<Type>: Make all properties of Type optionalReadonly<Type>: Make all properties of Type read-onlyPick<Type, Keys>: Select specified Keys from Type to construct a new typeRecord<Keys, Type>: Construct a object type with key type Keys and value type Type
[Note: Orgiinal utility type usage diagrams are not available, detailed examples are omitted.]