2.1 TypeScript类型概述

2.1.1 静态类型 vs 动态类型

JavaScript的动态类型

// JavaScript - 动态类型
let value = 42;        // number
value = "hello";       // string
value = true;          // boolean
value = { name: "Alice" }; // object

// 运行时才能发现类型错误
function add(a, b) {
    return a + b;
}

console.log(add(1, 2));      // 3
console.log(add(1, "2"));    // "12" - 可能不是预期结果

TypeScript的静态类型

// TypeScript - 静态类型
let value: number = 42;
value = "hello"; // 编译错误:Type 'string' is not assignable to type 'number'

function add(a: number, b: number): number {
    return a + b;
}

console.log(add(1, 2));      // 3
console.log(add(1, "2"));    // 编译错误:Argument of type 'string' is not assignable to parameter of type 'number'

2.1.2 类型注解和类型推断

类型注解(Type Annotations)

// 显式类型注解
let name: string = "Alice";
let age: number = 30;
let isActive: boolean = true;

// 函数参数和返回值类型注解
function greet(name: string): string {
    return `Hello, ${name}!`;
}

// 对象类型注解
let person: { name: string; age: number } = {
    name: "Bob",
    age: 25
};

类型推断(Type Inference)

// TypeScript自动推断类型
let name = "Alice";        // 推断为 string
let age = 30;              // 推断为 number
let isActive = true;       // 推断为 boolean

// 函数返回值类型推断
function add(a: number, b: number) {
    return a + b;  // 推断返回类型为 number
}

// 数组类型推断
let numbers = [1, 2, 3];   // 推断为 number[]
let mixed = [1, "hello"];  // 推断为 (string | number)[]

2.2 基本类型

2.2.1 原始类型

number类型

// 数字类型
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
let big: number = 1_000_000; // 数字分隔符

// 特殊数值
let notANumber: number = NaN;
let infinity: number = Infinity;
let negativeInfinity: number = -Infinity;

// 数学运算
function calculate(a: number, b: number): number {
    return a * b + Math.PI;
}

// 数字验证函数
function isValidNumber(value: number): boolean {
    return !isNaN(value) && isFinite(value);
}

string类型

// 字符串类型
let firstName: string = "John";
let lastName: string = 'Doe';

// 模板字符串
let fullName: string = `${firstName} ${lastName}`;
let greeting: string = `Hello, ${fullName}!
Welcome to TypeScript!`;

// 字符串方法
function formatName(name: string): string {
    return name.trim().toLowerCase().replace(/\b\w/g, l => l.toUpperCase());
}

// 字符串字面量类型
type Theme = "light" | "dark";
let currentTheme: Theme = "light";

// 字符串操作示例
function processText(text: string): {
    length: number;
    words: number;
    uppercase: string;
    lowercase: string;
} {
    return {
        length: text.length,
        words: text.split(/\s+/).length,
        uppercase: text.toUpperCase(),
        lowercase: text.toLowerCase()
    };
}

boolean类型

// 布尔类型
let isCompleted: boolean = false;
let isValid: boolean = true;

// 布尔运算
function canAccess(isLoggedIn: boolean, hasPermission: boolean): boolean {
    return isLoggedIn && hasPermission;
}

// 条件判断
function validateInput(input: string): boolean {
    return input.length > 0 && input.trim() !== "";
}

// 布尔转换
function toBooleanSafe(value: any): boolean {
    return Boolean(value);
}

2.2.2 特殊类型

null和undefined

// null和undefined类型
let nullValue: null = null;
let undefinedValue: undefined = undefined;

// 在严格模式下,null和undefined是不同的类型
let maybeString: string | null = null;
let maybeNumber: number | undefined = undefined;

// 可选属性
interface User {
    name: string;
    email?: string; // 等同于 email: string | undefined
}

function createUser(name: string, email?: string): User {
    return {
        name,
        ...(email && { email })
    };
}

// 空值检查
function processValue(value: string | null | undefined): string {
    if (value == null) { // 检查null和undefined
        return "No value";
    }
    return value.toUpperCase();
}

// 非空断言操作符
function getLength(value: string | null): number {
    return value!.length; // 断言value不为null
}

void类型

// void类型 - 表示没有返回值
function logMessage(message: string): void {
    console.log(message);
    // 没有return语句,或者return;
}

function processData(data: any[]): void {
    data.forEach(item => {
        console.log(item);
    });
    return; // 可以显式返回undefined
}

// void类型的变量只能赋值为undefined或null(在非严格模式下)
let unusable: void = undefined;

never类型

// never类型 - 表示永远不会有返回值
function throwError(message: string): never {
    throw new Error(message);
}

function infiniteLoop(): never {
    while (true) {
        // 无限循环
    }
}

// never类型在联合类型中会被忽略
type StringOrNever = string | never; // 等同于 string

// 用于详尽性检查
function assertNever(x: never): never {
    throw new Error("Unexpected object: " + x);
}

function processShape(shape: "circle" | "square"): number {
    switch (shape) {
        case "circle":
            return Math.PI;
        case "square":
            return 4;
        default:
            return assertNever(shape); // 确保所有情况都被处理
    }
}

any类型

// any类型 - 关闭类型检查
let anything: any = 42;
anything = "hello";
anything = true;
anything.foo.bar; // 不会有类型检查

// 应该避免使用any,但在某些情况下有用
function parseJSON(json: string): any {
    return JSON.parse(json);
}

// 逐步迁移JavaScript代码时使用
let legacyData: any = getLegacyData();

// 更好的替代方案
function parseJSONSafe<T>(json: string): T {
    return JSON.parse(json) as T;
}

// unknown类型是any的安全替代
let userInput: unknown = getUserInput();

// 使用unknown需要类型检查
if (typeof userInput === "string") {
    console.log(userInput.toUpperCase());
}

2.3 数组和元组

2.3.1 数组类型

基本数组语法

// 数组类型声明的两种方式
let numbers1: number[] = [1, 2, 3, 4, 5];
let numbers2: Array<number> = [1, 2, 3, 4, 5];

let strings: string[] = ["apple", "banana", "orange"];
let booleans: boolean[] = [true, false, true];

// 多维数组
let matrix: number[][] = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
];

// 混合类型数组
let mixed: (string | number)[] = [1, "hello", 2, "world"];

数组操作

// 数组方法的类型安全
const numbers: number[] = [1, 2, 3, 4, 5];

// map方法
const doubled: number[] = numbers.map(n => n * 2);
const strings: string[] = numbers.map(n => n.toString());

// filter方法
const evens: number[] = numbers.filter(n => n % 2 === 0);

// reduce方法
const sum: number = numbers.reduce((acc, curr) => acc + curr, 0);

// find方法
const found: number | undefined = numbers.find(n => n > 3);

// 数组解构
const [first, second, ...rest] = numbers;
console.log(first);  // number
console.log(second); // number
console.log(rest);   // number[]

只读数组

// 只读数组
const readonlyNumbers: readonly number[] = [1, 2, 3];
const readonlyNumbers2: ReadonlyArray<number> = [1, 2, 3];

// readonlyNumbers.push(4); // 错误:只读数组不能修改

// 函数参数使用只读数组
function processNumbers(numbers: readonly number[]): number {
    return numbers.reduce((sum, num) => sum + num, 0);
}

// 数组工具函数
function getFirstElement<T>(arr: readonly T[]): T | undefined {
    return arr[0];
}

function getLastElement<T>(arr: readonly T[]): T | undefined {
    return arr[arr.length - 1];
}

2.3.2 元组类型

基本元组

// 元组类型 - 固定长度和类型的数组
let person: [string, number] = ["Alice", 30];
let coordinate: [number, number] = [10, 20];

// 访问元组元素
const name = person[0]; // string
const age = person[1];  // number

// 元组解构
const [personName, personAge] = person;

// 元组作为函数返回值
function getNameAndAge(): [string, number] {
    return ["Bob", 25];
}

const [userName, userAge] = getNameAndAge();

可选元组元素

// 可选元组元素
type OptionalTuple = [string, number?];

let tuple1: OptionalTuple = ["hello"];
let tuple2: OptionalTuple = ["hello", 42];

// 剩余元素
type StringNumberBooleans = [string, number, ...boolean[]];

let example1: StringNumberBooleans = ["hello", 42];
let example2: StringNumberBooleans = ["hello", 42, true, false, true];

命名元组

// 命名元组(TypeScript 4.0+)
type Point = [x: number, y: number];
type Range = [start: number, end: number];

function calculateDistance(point1: Point, point2: Point): number {
    const [x1, y1] = point1;
    const [x2, y2] = point2;
    return Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
}

// 函数返回命名元组
function parseCoordinate(input: string): [x: number, y: number] | null {
    const match = input.match(/\((\d+),\s*(\d+)\)/);
    if (match) {
        return [parseInt(match[1]), parseInt(match[2])];
    }
    return null;
}

元组的实际应用

// 状态管理(类似React的useState)
type State<T> = [T, (newState: T) => void];

function createState<T>(initialValue: T): State<T> {
    let value = initialValue;
    
    const setValue = (newValue: T) => {
        value = newValue;
    };
    
    return [value, setValue];
}

const [count, setCount] = createState(0);

// 数据库查询结果
type QueryResult<T> = [data: T[], error: string | null, loading: boolean];

function useQuery<T>(query: string): QueryResult<T> {
    // 模拟查询逻辑
    return [[], null, false];
}

const [users, error, loading] = useQuery<User>("SELECT * FROM users");

2.4 对象类型

2.4.1 对象类型注解

基本对象类型

// 对象类型注解
let person: {
    name: string;
    age: number;
    email: string;
} = {
    name: "Alice",
    age: 30,
    email: "alice@example.com"
};

// 可选属性
let user: {
    name: string;
    age: number;
    email?: string; // 可选属性
} = {
    name: "Bob",
    age: 25
    // email可以省略
};

// 只读属性
let config: {
    readonly apiUrl: string;
    readonly timeout: number;
} = {
    apiUrl: "https://api.example.com",
    timeout: 5000
};

// config.apiUrl = "new url"; // 错误:只读属性不能修改

索引签名

// 索引签名 - 允许动态属性
interface StringDictionary {
    [key: string]: string;
}

let dict: StringDictionary = {
    name: "Alice",
    city: "New York",
    country: "USA"
};

// 数字索引签名
interface NumberArray {
    [index: number]: number;
}

let numbers: NumberArray = [1, 2, 3, 4, 5];

// 混合索引签名
interface MixedObject {
    name: string;           // 固定属性
    [key: string]: any;     // 动态属性
}

let obj: MixedObject = {
    name: "test",
    age: 30,
    active: true
};

嵌套对象

// 嵌套对象类型
interface Address {
    street: string;
    city: string;
    zipCode: string;
    country: string;
}

interface Person {
    name: string;
    age: number;
    address: Address;
    contacts: {
        email: string;
        phone?: string;
    };
}

const person: Person = {
    name: "Alice",
    age: 30,
    address: {
        street: "123 Main St",
        city: "New York",
        zipCode: "10001",
        country: "USA"
    },
    contacts: {
        email: "alice@example.com",
        phone: "+1-555-0123"
    }
};

// 深度访问
function getPersonInfo(person: Person): string {
    return `${person.name} lives in ${person.address.city}, ${person.address.country}`;
}

2.4.2 接口(Interface)

基本接口定义

// 接口定义
interface User {
    id: number;
    name: string;
    email: string;
    isActive: boolean;
}

// 使用接口
function createUser(userData: User): User {
    return {
        ...userData,
        id: Date.now()
    };
}

const newUser: User = {
    id: 1,
    name: "Alice",
    email: "alice@example.com",
    isActive: true
};

可选属性和只读属性

interface Product {
    readonly id: number;        // 只读属性
    name: string;
    price: number;
    description?: string;       // 可选属性
    category?: string;
    readonly createdAt: Date;
}

function createProduct(data: Omit<Product, 'id' | 'createdAt'>): Product {
    return {
        id: Math.random(),
        createdAt: new Date(),
        ...data
    };
}

const product = createProduct({
    name: "Laptop",
    price: 999.99,
    description: "High-performance laptop"
});

// product.id = 123; // 错误:只读属性

函数类型接口

// 函数类型接口
interface SearchFunction {
    (source: string, subString: string): boolean;
}

const mySearch: SearchFunction = function(source: string, subString: string): boolean {
    return source.indexOf(subString) > -1;
};

// 或者使用箭头函数
const mySearch2: SearchFunction = (source, subString) => {
    return source.includes(subString);
};

// 方法签名
interface Calculator {
    add(a: number, b: number): number;
    subtract(a: number, b: number): number;
    multiply(a: number, b: number): number;
    divide(a: number, b: number): number;
}

class BasicCalculator implements Calculator {
    add(a: number, b: number): number {
        return a + b;
    }
    
    subtract(a: number, b: number): number {
        return a - b;
    }
    
    multiply(a: number, b: number): number {
        return a * b;
    }
    
    divide(a: number, b: number): number {
        if (b === 0) throw new Error("Division by zero");
        return a / b;
    }
}

接口继承

// 基础接口
interface Animal {
    name: string;
    age: number;
}

// 继承接口
interface Dog extends Animal {
    breed: string;
    bark(): void;
}

interface Cat extends Animal {
    color: string;
    meow(): void;
}

// 多重继承
interface Pet extends Animal {
    owner: string;
}

interface ServiceDog extends Dog, Pet {
    serviceType: string;
    isWorking: boolean;
}

const serviceDog: ServiceDog = {
    name: "Buddy",
    age: 3,
    breed: "Golden Retriever",
    owner: "Alice",
    serviceType: "Guide Dog",
    isWorking: true,
    bark() {
        console.log("Woof!");
    }
};

2.4.3 类型别名(Type Aliases)

基本类型别名

// 类型别名
type UserID = number;
type UserName = string;
type UserEmail = string;

// 使用类型别名
function getUserById(id: UserID): User | null {
    // 实现逻辑
    return null;
}

// 联合类型别名
type Status = "pending" | "approved" | "rejected";
type Theme = "light" | "dark" | "auto";

function setTheme(theme: Theme): void {
    document.body.className = theme;
}

// 复杂类型别名
type EventHandler<T> = (event: T) => void;
type ApiResponse<T> = {
    data: T;
    status: number;
    message: string;
};

接口 vs 类型别名

// 接口
interface UserInterface {
    name: string;
    age: number;
}

// 类型别名
type UserType = {
    name: string;
    age: number;
};

// 接口可以被扩展
interface UserInterface {
    email: string; // 接口合并
}

// 类型别名不能被重新声明
// type UserType = { email: string; } // 错误

// 类型别名可以表示联合类型
type StringOrNumber = string | number;

// 接口不能表示联合类型
// interface StringOrNumber = string | number; // 错误

// 类型别名可以使用计算属性
type Keys = "name" | "age";
type UserRecord = {
    [K in Keys]: string;
};

2.5 函数类型

2.5.1 函数类型注解

基本函数类型

// 函数声明
function add(a: number, b: number): number {
    return a + b;
}

// 函数表达式
const multiply = function(a: number, b: number): number {
    return a * b;
};

// 箭头函数
const divide = (a: number, b: number): number => {
    if (b === 0) throw new Error("Division by zero");
    return a / b;
};

// 完整的函数类型注解
const subtract: (a: number, b: number) => number = (a, b) => a - b;

可选参数和默认参数

// 可选参数
function greet(name: string, greeting?: string): string {
    return `${greeting || "Hello"}, ${name}!`;
}

console.log(greet("Alice"));           // "Hello, Alice!"
console.log(greet("Bob", "Hi"));       // "Hi, Bob!"

// 默认参数
function createUser(name: string, age: number = 18, isActive: boolean = true): User {
    return {
        id: Math.random(),
        name,
        age,
        isActive
    };
}

// 剩余参数
function sum(...numbers: number[]): number {
    return numbers.reduce((total, num) => total + num, 0);
}

console.log(sum(1, 2, 3, 4, 5)); // 15

// 混合参数
function logMessage(level: string, message: string, ...details: any[]): void {
    console.log(`[${level}] ${message}`, ...details);
}

logMessage("INFO", "User logged in", { userId: 123, timestamp: new Date() });

函数重载

// 函数重载声明
function parseValue(value: string): string;
function parseValue(value: number): number;
function parseValue(value: boolean): boolean;

// 函数实现
function parseValue(value: string | number | boolean): string | number | boolean {
    if (typeof value === "string") {
        return value.trim();
    } else if (typeof value === "number") {
        return Math.round(value);
    } else {
        return value;
    }
}

// 使用重载
const str = parseValue("  hello  "); // string
const num = parseValue(3.14);        // number
const bool = parseValue(true);       // boolean

// 更复杂的重载示例
interface Contact {
    name: string;
    email?: string;
    phone?: string;
}

function createContact(name: string): Contact;
function createContact(name: string, email: string): Contact;
function createContact(name: string, email: string, phone: string): Contact;

function createContact(name: string, email?: string, phone?: string): Contact {
    const contact: Contact = { name };
    if (email) contact.email = email;
    if (phone) contact.phone = phone;
    return contact;
}

2.5.2 高阶函数

函数作为参数

// 回调函数类型
type Callback<T> = (item: T) => void;
type Predicate<T> = (item: T) => boolean;
type Transformer<T, U> = (item: T) => U;

// 高阶函数示例
function forEach<T>(array: T[], callback: Callback<T>): void {
    for (const item of array) {
        callback(item);
    }
}

function filter<T>(array: T[], predicate: Predicate<T>): T[] {
    const result: T[] = [];
    for (const item of array) {
        if (predicate(item)) {
            result.push(item);
        }
    }
    return result;
}

function map<T, U>(array: T[], transformer: Transformer<T, U>): U[] {
    const result: U[] = [];
    for (const item of array) {
        result.push(transformer(item));
    }
    return result;
}

// 使用示例
const numbers = [1, 2, 3, 4, 5];

forEach(numbers, num => console.log(num));
const evens = filter(numbers, num => num % 2 === 0);
const doubled = map(numbers, num => num * 2);
const strings = map(numbers, num => num.toString());

函数作为返回值

// 返回函数的函数
function createMultiplier(factor: number): (value: number) => number {
    return (value: number) => value * factor;
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5)); // 10
console.log(triple(4)); // 12

// 柯里化函数
function curry<T, U, V>(fn: (a: T, b: U) => V): (a: T) => (b: U) => V {
    return (a: T) => (b: U) => fn(a, b);
}

const add = (a: number, b: number) => a + b;
const curriedAdd = curry(add);
const add5 = curriedAdd(5);

console.log(add5(3)); // 8

// 装饰器模式
function withLogging<T extends any[], U>(
    fn: (...args: T) => U
): (...args: T) => U {
    return (...args: T) => {
        console.log(`Calling function with args:`, args);
        const result = fn(...args);
        console.log(`Function returned:`, result);
        return result;
    };
}

const loggedAdd = withLogging(add);
console.log(loggedAdd(2, 3)); // 带日志的加法

2.6 联合类型和交叉类型

2.6.1 联合类型(Union Types)

基本联合类型

// 联合类型
type StringOrNumber = string | number;
type Status = "loading" | "success" | "error";

function formatValue(value: StringOrNumber): string {
    if (typeof value === "string") {
        return value.toUpperCase();
    } else {
        return value.toString();
    }
}

// 函数参数联合类型
function processId(id: string | number): string {
    // 类型守卫
    if (typeof id === "string") {
        return id.toLowerCase();
    } else {
        return id.toString();
    }
}

// 数组联合类型
type MixedArray = (string | number | boolean)[];
const mixed: MixedArray = ["hello", 42, true, "world", 3.14];

对象联合类型

// 不同形状的对象联合
interface Circle {
    kind: "circle";
    radius: number;
}

interface Rectangle {
    kind: "rectangle";
    width: number;
    height: number;
}

interface Triangle {
    kind: "triangle";
    base: number;
    height: number;
}

type Shape = Circle | Rectangle | Triangle;

// 使用判别联合
function calculateArea(shape: Shape): number {
    switch (shape.kind) {
        case "circle":
            return Math.PI * shape.radius ** 2;
        case "rectangle":
            return shape.width * shape.height;
        case "triangle":
            return (shape.base * shape.height) / 2;
        default:
            // 详尽性检查
            const _exhaustiveCheck: never = shape;
            return _exhaustiveCheck;
    }
}

联合类型的类型守卫

// 自定义类型守卫
function isString(value: unknown): value is string {
    return typeof value === "string";
}

function isNumber(value: unknown): value is number {
    return typeof value === "number";
}

function processValue(value: unknown): string {
    if (isString(value)) {
        return value.toUpperCase(); // TypeScript知道这里value是string
    } else if (isNumber(value)) {
        return value.toString();    // TypeScript知道这里value是number
    } else {
        return "Unknown type";
    }
}

// in操作符类型守卫
function isCircle(shape: Shape): shape is Circle {
    return "radius" in shape;
}

function isRectangle(shape: Shape): shape is Rectangle {
    return "width" in shape && "height" in shape;
}

function getShapeInfo(shape: Shape): string {
    if (isCircle(shape)) {
        return `Circle with radius ${shape.radius}`;
    } else if (isRectangle(shape)) {
        return `Rectangle ${shape.width}x${shape.height}`;
    } else {
        return `Triangle with base ${shape.base} and height ${shape.height}`;
    }
}

2.6.2 交叉类型(Intersection Types)

基本交叉类型

// 交叉类型 - 组合多个类型
interface Person {
    name: string;
    age: number;
}

interface Employee {
    employeeId: number;
    department: string;
}

type PersonEmployee = Person & Employee;

const employee: PersonEmployee = {
    name: "Alice",
    age: 30,
    employeeId: 12345,
    department: "Engineering"
};

// 函数参数交叉类型
function processEmployee(person: Person & Employee): string {
    return `${person.name} (ID: ${person.employeeId}) works in ${person.department}`;
}

混合对象类型

// 混合多个接口
interface Timestamped {
    timestamp: Date;
}

interface Tagged {
    tags: string[];
}

type TimestampedTagged<T> = T & Timestamped & Tagged;

interface BlogPost {
    title: string;
    content: string;
    author: string;
}

type EnhancedBlogPost = TimestampedTagged<BlogPost>;

const post: EnhancedBlogPost = {
    title: "TypeScript Guide",
    content: "Learning TypeScript...",
    author: "Alice",
    timestamp: new Date(),
    tags: ["typescript", "programming", "tutorial"]
};

函数类型交叉

// 函数类型交叉
type Logger = {
    log: (message: string) => void;
};

type Counter = {
    count: number;
    increment: () => void;
};

type LoggerCounter = Logger & Counter;

const loggerCounter: LoggerCounter = {
    count: 0,
    log(message: string) {
        console.log(`[${this.count}] ${message}`);
    },
    increment() {
        this.count++;
    }
};

loggerCounter.log("Hello");    // [0] Hello
loggerCounter.increment();
loggerCounter.log("World");    // [1] World

2.7 类型断言和类型守卫

2.7.1 类型断言

基本类型断言

// 类型断言 - 告诉编译器变量的确切类型
let someValue: unknown = "this is a string";

// 角括号语法(在JSX中不可用)
let strLength1: number = (<string>someValue).length;

// as语法(推荐)
let strLength2: number = (someValue as string).length;

// DOM元素类型断言
const inputElement = document.getElementById("myInput") as HTMLInputElement;
inputElement.value = "Hello";

// 非空断言操作符
function processElement(element: HTMLElement | null) {
    // 确信element不为null
    element!.style.display = "none";
}

常量断言

// 常量断言
const colors = ["red", "green", "blue"] as const;
// colors的类型是 readonly ["red", "green", "blue"]

const config = {
    apiUrl: "https://api.example.com",
    timeout: 5000
} as const;
// config的类型是 { readonly apiUrl: "https://api.example.com"; readonly timeout: 5000; }

// 枚举替代
const Direction = {
    Up: "UP",
    Down: "DOWN",
    Left: "LEFT",
    Right: "RIGHT"
} as const;

type Direction = typeof Direction[keyof typeof Direction];
// Direction类型是 "UP" | "DOWN" | "LEFT" | "RIGHT"

2.7.2 类型守卫

内置类型守卫

// typeof类型守卫
function processValue(value: string | number): string {
    if (typeof value === "string") {
        return value.toUpperCase();
    } else {
        return value.toString();
    }
}

// instanceof类型守卫
class Dog {
    bark() {
        console.log("Woof!");
    }
}

class Cat {
    meow() {
        console.log("Meow!");
    }
}

function makeSound(animal: Dog | Cat) {
    if (animal instanceof Dog) {
        animal.bark();
    } else {
        animal.meow();
    }
}

// in操作符类型守卫
interface Fish {
    swim(): void;
}

interface Bird {
    fly(): void;
}

function move(animal: Fish | Bird) {
    if ("swim" in animal) {
        animal.swim();
    } else {
        animal.fly();
    }
}

自定义类型守卫

// 自定义类型守卫函数
function isString(value: any): value is string {
    return typeof value === "string";
}

function isNumber(value: any): value is number {
    return typeof value === "number" && !isNaN(value);
}

function isArray<T>(value: any): value is T[] {
    return Array.isArray(value);
}

// 复杂对象类型守卫
interface User {
    id: number;
    name: string;
    email: string;
}

function isUser(obj: any): obj is User {
    return obj &&
           typeof obj.id === "number" &&
           typeof obj.name === "string" &&
           typeof obj.email === "string";
}

function processUserData(data: unknown) {
    if (isUser(data)) {
        // TypeScript现在知道data是User类型
        console.log(`User: ${data.name} (${data.email})`);
    } else {
        console.log("Invalid user data");
    }
}

// 泛型类型守卫
function isArrayOf<T>(value: any, guard: (item: any) => item is T): value is T[] {
    return Array.isArray(value) && value.every(guard);
}

const data: unknown = [1, 2, 3, 4, 5];
if (isArrayOf(data, isNumber)) {
    // data现在是number[]类型
    const sum = data.reduce((a, b) => a + b, 0);
}

本章练习

练习1:基本类型

  1. 创建不同类型的变量并进行类型注解
  2. 实现一个函数,接受多种类型的参数
  3. 使用类型推断创建复杂的数据结构

练习2:数组和元组

  1. 创建不同类型的数组并实现操作函数
  2. 使用元组表示坐标点并实现距离计算
  3. 实现一个通用的数组工具库

练习3:对象和接口

  1. 设计用户管理系统的接口
  2. 实现接口继承和组合
  3. 创建灵活的配置对象类型

练习4:函数类型

  1. 实现函数重载
  2. 创建高阶函数
  3. 使用类型守卫处理联合类型

练习5:联合和交叉类型

  1. 设计状态管理系统
  2. 实现类型安全的事件系统
  3. 创建可扩展的插件架构

本章总结

在本章中,我们深入学习了TypeScript的基础类型系统:

  1. 基本类型:掌握了原始类型和特殊类型的使用
  2. 数组和元组:学会了集合类型的定义和操作
  3. 对象类型:理解了接口和类型别名的区别和应用
  4. 函数类型:掌握了函数签名和高阶函数的类型定义
  5. 联合和交叉类型:学会了复杂类型的组合和使用
  6. 类型断言和守卫:掌握了类型安全的编程技巧

下一章我们将学习TypeScript的接口和类,这是面向对象编程的核心概念。