下篇:TypeScript 高级特性(高级类型、类型操作、最佳实践)

📚 下篇:高级特性

  • 类型转换与类型断言
  • 类型守卫(typeof, instanceof, in, 自定义守卫)
  • 高级类型特性(条件类型、映射类型、模板字面量类型、索引类型)
  • 内置工具类型大全(Partial, Pick, Omit, Record 等)
  • 类型声明文件(.d.ts)
  • 最佳实践和编码规范
  • 学习路线建议

📚 目录

  1. 类型转换与类型断言
  2. 类型守卫
  3. 高级类型特性
  4. 类型声明文件
  5. 最佳实践
  6. 学习路线与建议

1. 类型转换与类型断言

1.1 类型转换方法

typescript 复制代码
// 内置转换函数
let strNum: string = "123";
let num: number = Number(strNum);
let parsed: number = parseInt(strNum);
let float: number = parseFloat("3.14");

let numStr: number = 42;
let str: string = String(numStr);

let truthy: any = "hello";
let bool: boolean = Boolean(truthy);

1.2 类型断言

类型断言允许你告诉编译器具体是什么类型。

typescript 复制代码
// 场景 1:已知更具体的类型
let rootElement: any = document.getElementById("app");
let htmlElement: HTMLElement = rootElement as HTMLElement;
let divElement: HTMLDivElement = rootElement as HTMLDivElement;

// 场景 2:联合类型 narrowing
function getLength(value: string | string[]) {
    if ((value as string).length) {
        return (value as string).length;
    } else {
        return (value as string[]).length;
    }
}

1.3 两种断言语法

typescript 复制代码
let someValue: any = "this is a string";

// 方式 1:as 语法(推荐)
let strLength: number = (someValue as string).length;

// 方式 2:尖括号语法
let strLength2: number = (<string>someValue).length;

2. 类型守卫

类型守卫是在运行时检查类型的方法。

2.1 typeof 守卫

typescript 复制代码
function padLeft(value: string, padding: string | number) {
    if (typeof padding === "number") {
        return Array(padding + 1).join(" ") + value;
    }
    if (typeof padding === "string") {
        return padding + value;
    }
    throw new Error("Invalid padding");
}

// 实际应用
function process(value: string | number) {
    if (typeof value === "string") {
        // 在这里 value 被推断为 string
        console.log(value.toUpperCase());
    } else {
        // 在这里 value 被推断为 number
        console.log(value.toFixed(2));
    }
}

2.2 instanceof 守卫

typescript 复制代码
class Bird {
    fly() { console.log("flying"); }
    layEggs() { console.log("laying eggs"); }
}

class Fish {
    swim() { console.log("swimming"); }
    layEggs() { console.log("laying eggs"); }
}

function move(pet: Bird | Fish) {
    if (pet instanceof Fish) {
        pet.swim();
    } else {
        pet.fly();
    }
}

// 实际案例
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();
    }
}

2.3 in 守卫

typescript 复制代码
interface Bird {
    fly(): void;
    layEggs(): void;
}

interface Fish {
    swim(): void;
    layEggs(): void;
}

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

2.4 自定义类型守卫

typescript 复制代码
// 使用类型谓词
function isFish(pet: Bird | Fish): pet is Fish {
    return (pet as Fish).swim !== undefined;
}

// 使用守卫函数
if (isFish(animal)) {
    animal.swim(); // animal 被推断为 Fish 类型
}

3. 高级类型特性

3.1 条件类型(Conditional Types)

typescript 复制代码
// 根据条件选择类型
type IsString<T> = T extends string ? true : false;

type A = IsString<string>;  // true
type B = IsString<number>;  // false

// 实际应用:提取返回类型
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

function fn(): string {
    return "hello";
}

type FnReturn = ReturnType<typeof fn>; // string

3.2 映射类型(Mapped Types)

typescript 复制代码
// 基于现有类型创建新类型

// Readonly - 将所有属性设为只读
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

interface Person {
    name: string;
    age: number;
}

type ReadonlyPerson = Readonly<Person>;

// Partial - 将所有属性设为可选
type Partial<T> = {
    [P in keyof T]?: T[P];
};

type PartialPerson = Partial<Person>;

// Pick - 选择特定属性
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

type NameOnly = Pick<Person, "name">;

// Omit - 省略特定属性
type Omit<T, K extends keyof T> = {
    [P in Exclude<keyof T, K>]: T[P];
};

type AgeOnly = Omit<Person, "name">;

3.3 模板字面量类型

typescript 复制代码
// 使用模板字符串定义类型
type Greeting = `Hello, ${string}!`;

let greeting1: Greeting = "Hello, Alice!";
let greeting2: Greeting = "Hello, Bob!";

// 组合使用
type EventName = "click" | "hover" | "focus";
type Handler = `${EventName}Handler`;

type ClickHandler = "clickHandler"; // ✅
type HoverHandler = "hoverHandler"; // ✅

3.4 索引类型(Index Types)

typescript 复制代码
// 索引类型查询
interface Person {
    name: string;
    age: number;
    city: string;
}

// 获取属性的类型
type PersonName = Person["name"];     // string
type PersonAge = Person["age"];       // number

// 获取所有属性的类型
type PersonKeys = keyof Person;       // "name" | "age" | "city"
type PersonValues = Person[keyof Person]; // string | number

// 实际应用
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
    return obj[key];
}

let person = { name: "Alice", age: 30 };
let name = getProperty(person, "name"); // string

3.5 工具类型(Utility Types)

TypeScript 内置了常用的工具类型:

typescript 复制代码
// Partial<T> - 将 T 的所有属性设为可选
interface Todo {
    title: string;
    description: string;
}

function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
    // ...
}

// Required<T> - 将 T 的所有属性设为必需
type RequiredTodo = Required<Todo>;

// Readonly<T> - 将 T 的所有属性设为只读
type ReadonlyTodo = Readonly<Todo>;

// Record<K, T> - 构造一个对象类型,属性键为 K,属性值为 T
interface PageInfo {
    title: string;
}

type Pages = "home" | "about" | "contact";
const nav: Record<Pages, PageInfo> = {
    home: { title: "Home" },
    about: { title: "About" },
    contact: { title: "Contact" }
};

// Pick<T, K> - 从 T 中选择一组属性 K
type TodoPreview = Pick<Todo, "title">;

// Omit<T, K> - 从 T 中排除一组属性 K
type TodoInfo = Omit<Todo, "description">;

// Exclude<T, U> - 从 T 中排除可分配给 U 的类型
type T0 = Exclude<"a" | "b" | "c", "a">; // "b" | "c"

// Extract<T, U> - 从 T 中提取可分配给 U 的类型
type T1 = Extract<"a" | "b" | "c", "a" | "b">; // "a" | "b"

// NonNullable<T> - 从 T 中排除 null 和 undefined
type T2 = NonNullable<string | number | null | undefined>; // string | number

// Parameters<T> - 获取函数参数类型
type T3 = Parameters<(s: string, n: number) => void>; // [string, number]

// ReturnType<T> - 获取函数返回值类型
type T4 = ReturnType<() => string>; // string

4. 类型声明文件

4.1 什么是类型声明文件?

类型声明文件(.d.ts)用于为 JavaScript 代码提供类型信息,让 TypeScript 能够理解非 TypeScript 代码。

4.2 模块声明

typescript 复制代码
// 声明 CSS 模块
declare module '*.css' {
    const content: any;
    export default content;
}

// 声明 Less 模块
declare module '*.less' {
    const content: any;
    export default content;
}

// 声明 SCSS 模块
declare module '*.scss' {
    const content: any;
    export default content;
}

// 声明图片模块
declare module '*.png' {
    const src: string;
    export default src;
}

// 声明 JSON 模块
declare module '*.json' {
    const value: any;
    export default value;
}

4.3 使用场景

typescript 复制代码
// 在 Vue/React 项目中导入样式
import './style.css';
import styles from './theme.less';

// 在 Vite/Webpack 中使用
// tsconfig.json 中需要配置:
// {
//   "compilerOptions": {
//     "moduleResolution": "node",
//     "allowImportingTsExtensions": true
//   }
// }

4.4 全局声明

typescript 复制代码
// 声明全局变量
declare const API_URL: string;

// 声明全局函数
declare function ajax(url: string): Promise<any>;

// 扩展全局命名空间
declare global {
    interface Window {
        myPlugin: any;
    }
}

5. 最佳实践

5.1 类型选择优先级

typescript 复制代码
// ✅ 优先使用具体类型
let name: string = "Alice";
let age: number = 30;

// ✅ 其次使用接口或类型别名
interface User {
    id: number;
    name: string;
}

// ⚠️ 谨慎使用 any
let value: any; // 避免

// ✅ 使用 unknown 代替 any
let unknownValue: unknown;

// ✅ 使用类型推断
let count = 0; // 不需要显式标注 : number

5.2 接口设计原则

typescript 复制代码
// ✅ 保持接口简洁
interface User {
    id: number;
    name: string;
    email: string;
}

// ✅ 使用可选属性
interface Config {
    debug?: boolean;
    timeout?: number;
}

// ✅ 使用只读属性
interface ImmutablePoint {
    readonly x: number;
    readonly y: number;
}

// ✅ 接口继承扩展
interface Animal {
    name: string;
}

interface Dog extends Animal {
    breed: string;
}

5.3 泛型使用指南

typescript 复制代码
// ✅ 有意义的泛型命名
function identity<T>(arg: T): T {
    return arg;
}

// ✅ 多个泛型参数
function merge<T, U>(obj1: T, obj2: U): T & U {
    return { ...obj1, ...obj2 };
}

// ✅ 泛型约束
function logLength<T extends { length: number }>(arg: T): void {
    console.log(arg.length);
}

logLength("hello"); // ✅
// logLength(42);   // ❌

5.4 避免的陷阱

typescript 复制代码
// ❌ 过度使用 any
function process(data: any): any {
    return data;
}

// ✅ 使用泛型
function process<T>(data: T): T {
    return data;
}

// ❌ 类型断言滥用
let value: any = "hello";
let length = (value as string).length;

// ✅ 先进行类型检查
if (typeof value === "string") {
    let length = value.length;
}

// ❌ 忽略严格模式
// tsconfig.json 中应启用 strict: true

// ✅ 启用所有严格检查
{
  "compilerOptions": {
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true
  }
}

5.5 项目配置建议

json 复制代码
{
  "compilerOptions": {
    // 基础配置
    "target": "ES2020",
    "module": "ESNext",
    "lib": ["ES2020", "DOM"],
    
    // 严格模式
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    
    // 模块解析
    "moduleResolution": "node",
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    
    // 输出
    "outDir": "./dist",
    "declaration": true,
    "sourceMap": true,
    
    // 代码质量
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitThis": true,
    "alwaysStrict": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "**/*.test.ts"]
}

5.6 编码规范

typescript 复制代码
// ✅ 好的实践
interface ButtonProps {
    label: string;
    onClick: () => void;
    disabled?: boolean;
}

type EventType = 'click' | 'hover' | 'focus';

// ❌ 避免使用 any
let data: any; // 不好
let data: unknown; // 更好

// ✅ 使用类型推断
const arr = [1, 2, 3]; // 自动推断为 number[]

// ✅ 推荐:定义对象结构
interface User {
    id: number;
    name: string;
    email: string;
}

// ✅ 推荐:定义函数类型
interface ApiFunction {
    (url: string, data?: any): Promise<any>;
}

// ✅ 推荐:定义类结构
interface Service {
    init(): void;
    destroy(): void;
}

class UserService implements Service {
    init() { console.log('初始化'); }
    destroy() { console.log('销毁'); }
}

6. 学习路线与建议

6.1 学习路线

复制代码
初级阶段
    ↓
基础类型(string, number, boolean)
接口和类型别名
枚举、元组、数组
    ↓
中级阶段
    ↓
泛型概念和应用
接口继承和实现
类型推断和类型守卫
联合类型和交叉类型
    ↓
高级阶段
    ↓
条件类型和映射类型
类型声明文件编写
高级工具类型(Pick, Omit, Partial 等)
实际项目应用

6.2 实战最佳实践

何时使用接口?
typescript 复制代码
// ✅ 推荐:定义对象结构
interface User {
    id: number;
    name: string;
    email: string;
}

// ✅ 推荐:定义函数类型
interface ApiFunction {
    (url: string, data?: any): Promise<any>;
}

// ✅ 推荐:定义类结构
interface Service {
    init(): void;
    destroy(): void;
}

class UserService implements Service {
    init() { console.log('初始化'); }
    destroy() { console.log('销毁'); }
}
何时使用泛型?
typescript 复制代码
// ✅ 推荐:通用工具函数
function wrapInArray<T>(value: T): T[] {
    return [value];
}

// ✅ 推荐:API 响应类型
interface ApiResponse<T> {
    code: number;
    data: T;
    message: string;
}

// 使用
const response: ApiResponse<User> = {
    code: 200,
    data: { id: 1, name: '张三', email: 'test@example.com' },
    message: 'success'
};

6.3 常见问题解答

Q1: Interface 和 Type 选哪个?
A:

  • 定义对象结构 → Interface
  • 定义联合类型 → Type
  • 需要被类实现 → Interface
  • 需要类型别名 → Type

Q2: 什么时候用泛型?
A: 当你需要编写可复用 的代码,且这个代码需要处理多种类型时。

Q3: any 和 unknown 有什么区别?
A:

  • any: 放弃类型检查,不安全
  • unknown: 需要类型收窄后才能使用,更安全

Q4: 如何选择合适的类型注解?
A:

  1. 优先让 TypeScript 自动推断
  2. 函数参数和返回值明确标注
  3. 对象和数组使用接口或类型别名
  4. 避免使用 any

📝 下篇总结

关键要点

类型断言用于告诉编译器具体类型

类型守卫在运行时检查类型

掌握条件类型、映射类型等高级特性

理解并使用内置工具类型

遵循最佳实践,编写类型安全的代码

完整学习检查清单

上篇内容回顾
  • TypeScript 概述和优势
  • 编译器安装和配置
  • 基础类型(string, number, boolean, array)
  • 联合类型、交叉类型
  • 枚举和元组
中篇内容回顾
  • 接口定义和使用
  • 类实现接口
  • Interface vs Type
  • Interface vs 抽象类
  • 泛型函数、接口、类
下篇内容回顾
  • 类型转换和类型断言
  • 类型守卫(typeof, instanceof, in)
  • 条件类型和映射类型
  • 内置工具类型
  • 类型声明文件
  • 最佳实践和项目配置

🎯 TypeScript 的核心价值

TypeScript 的核心价值在于:

  • 类型安全:在编译时发现错误
  • 代码提示:IDE 智能补全
  • 重构友好:修改代码更自信
  • 文档即代码:类型即文档

记住:TypeScript 的目标不是限制你,而是帮助你写出更好的代码!


📖 快速参考表

基础类型

类型 语法 示例
字符串 string let name: string = 'tom'
数字 number let age: number = 18
布尔 boolean let isOk: boolean = true
数组 type[] let arr: number[] = [1,2,3]
元组 [T, U] let tuple: [string, number]
枚举 enum enum Color { Red, Green }
任意 any let value: any = 4
空值 void function(): void {}
永不 never function(): never {}
对象 object let obj: object = {}

常用工具类型

工具类型 作用 示例
Partial<T> 将属性设为可选 Partial<User>
Required<T> 将属性设为必需 Required<User>
Readonly<T> 将属性设为只读 Readonly<User>
Pick<T, K> 选择特定属性 Pick<User, 'name'>
Omit<T, K> 省略特定属性 Omit<User, 'age'>
Record<K, T> 构造对象类型 Record<string, number>
ReturnType<T> 获取返回类型 ReturnType<fn>
Parameters<T> 获取参数类型 Parameters<fn>

相关推荐
吴声子夜歌3 小时前
TypeScript——内置工具类型、类型查询、类型断言和类型细化
linux·ubuntu·typescript
楚轩努力变强4 小时前
2026 年前端进阶:端侧大模型 + WebGPU,从零打造高性能 AI 原生前端应用
前端·typescript·大模型·react·webgpu·ai原生·高性能前端
吴声子夜歌4 小时前
TypeScript——索引类型、映射对象类型、条件类型
git·ubuntu·typescript
吴声子夜歌4 小时前
TypeScript——局部类型、联合类型、交叉类型
javascript·git·typescript
紫_龙21 小时前
最新版vue3+TypeScript开发入门到实战教程之路由详解三
前端·javascript·typescript
belldeep1 天前
nodejs:Vite + Svelte + ts 入门示例
typescript·node.js·ts·vite·svelte
We་ct1 天前
LeetCode 4. 寻找两个正序数组的中位数:二分优化思路详解
前端·数据结构·算法·leetcode·typescript·二分
吴声子夜歌1 天前
TypeScript——BigInt、展开运算符、解构和可选链运算符
前端·javascript·typescript