编程进阶网 编程进阶网
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接

杨充

专注编程 · 终身学习者
首页
  • 计算机原理
  • 操作系统
  • 网络协议
  • 数据库原理
  • 面向对象
  • 设计原则
  • 设计模式
  • 系统架构
  • 性能优化
  • 编程原理
  • 方案设计
  • 稳定可靠
  • 工程运维
  • 基础认知
  • 线性结构
  • 树与哈希
  • 工业级实现
  • 算法思想
  • 实战与综合
  • 算法题考核
  • C语言入门
  • C综合案例
  • C专栏博客
  • C标准集库
  • C++入门教程
  • C++综合案例
  • C++专栏博客
  • C++开发技巧
  • Java入门教程
  • Java综合案例
  • Java专栏博客
  • Go入门教程
  • Go综合案例
  • Go专栏博客
  • Go开发技巧
  • JavaScript入门
  • JavaScript高级
  • Android库解读
  • Android专栏
  • Android智能硬件
  • iOS ObjC入门
  • iOS Swift入门
  • iOS入门精通
  • Web之Html手册
  • Web之TypeScript
  • Web之Vue高级进阶
  • Linux之QML入门
  • Linux之QT核心库
  • Linux实践开发
  • Python教程
  • Shell&Bash教程
  • 工具脚本
  • 自动化脚本
  • 质量保障
  • 产品思考
  • 软实力
  • 开发流程
  • Git应用
  • 技术模版
  • 技术规范
  • Markdown
  • Mermaid
  • 开源协议
  • JSON工具
  • 文本工具
  • 图片处理
  • 文档转化
  • 代码压缩
  • 关于我
  • 自我精进
  • 职场管理
  • 职场面试
  • 心情杂货
  • 友情链接
  • README
  • 质量保障

  • 产品思考

  • 软实力

  • 开发流程

  • Git应用

  • 技术模版

  • 技术规范

    • 技术规范
    • C++编程代码规范指南
    • Java编程代码规范指南
    • JavaScript编程规范指南
    • TypeScript编程规范指南
      • 目录
      • 01.规范概述
        • 1.1 为何需要 TypeScript 规范
        • 1.2 核心目标
        • 1.3 要求等级
      • 02.命名规范
      • 03.类型与接口
        • 3.1 interface 与 type 的选择
        • 3.2 辨识联合类型(Discriminated Union)【推荐】
        • 3.3 类型收窄(Type Narrowing)【推荐】
        • 3.4 satisfies 操作符(TS 4.9+)【推荐】
      • 04.函数规范
        • 4.1 参数与返回值类型
        • 4.3 this 参数类型 【推荐】
      • 05.类设计规范
      • 06.导入与模块
      • 07.空安全与可选链
      • 08.泛型使用规范
        • 8.1 基础泛型与约束
        • 8.2 条件类型与 infer 【推荐】
        • 8.3 模板字面量类型(TS 4.4+)【推荐】
      • 09.枚举与常量
      • 10.异步与 Promise
      • 09.枚举与常量
      • 11.工具链与自动化
        • 11.1 tsconfig 严格模式
        • 11.2 ESLint 与 Prettier
        • 11.3 CI 集成
      • 12.代码审查清单
      • 13.常见陷阱速查
        • 13.1 类型陷阱
        • 13.2 泛型陷阱
        • 13.3 工程陷阱
    • Python编程代码规范指南
    • Go编程代码规范指南
    • Kotlin编程代码规范指南
    • Swift编程代码规范指南
    • Rust编程代码规范指南
    • Shell编程代码规范指南
    • 项目代码提交规范
  • markdown

  • mermaid

  • license

  • 博客部署

  • 技术招聘

  • 测试经验

  • 技术
  • 技术规范
杨充
2020-09-10
目录

TypeScript编程规范指南

# TypeScript编程代码规范指南

基于 TypeScript ESLint (opens new window) 推荐配置。

# 目录

  • 01.规范概述
    • 1.1 为何需要 TypeScript 规范
    • 1.2 核心目标
    • 1.3 要求等级
  • 02.命名规范
  • 03.类型与接口
    • 3.1 interface-与-type-的选择
    • 3.2 辨识联合类型
    • 3.3 类型收窄
    • 3.4 satisfies-操作符
  • 04.函数规范
    • 4.1 参数与返回值类型
    • 4.2 函数重载
    • 4.3 this-参数类型
  • 05.类设计规范
  • 06.导入与模块
  • 07.空安全与可选链
  • 08.泛型使用规范
    • 8.1 基础泛型与约束
    • 8.2 条件类型与-infer
    • 8.3 模板字面量类型
  • 09.枚举与常量
  • 10.异步与 Promise
  • 11.工具链与自动化
    • 11.1 tsconfig-严格模式
    • 11.2 ESLint-与-Prettier
    • 11.3 CI-集成
  • 12.代码审查清单
  • 13.常见陷阱速查
    • 13.1 类型陷阱
    • 13.2 泛型陷阱
    • 13.3 工程陷阱

# 01.规范概述

# 1.1 为何需要 TypeScript 规范

疑惑:TypeScript 编译器已经能检查类型了,为什么还需要编码规范?

答疑:TypeScript 的类型系统非常灵活——同一目标有 5 种类型实现方式。interface 还是 type?unknown 还是 any?enum 还是 as const?规范的本质是在灵活性中统一选择,让团队代码像一个模式的重复应用。

# 1.2 核心目标

目标 说明
类型安全 利用 TS 类型系统在编译期消除一类运行时 bug
可维护性 类型即文档,新成员看类型签名就能理解 API
一致性 全项目 interface/type、泛型风格统一
可审查性 Code Review 聚焦逻辑和类型设计,而非风格争论

# 1.3 要求等级

  • 必须(Mandatory):必须采用(CI 中强制检查)
  • 推荐(Preferable):理应采用,特殊情况可不采用
  • 可选(Optional):自行决定

# 02.命名规范

类型 规范 示例
变量/函数 camelCase userName, getUserById()
类/接口/类型 PascalCase UserService, ApiResponse
常量 UPPER_CASE 或 camelCase MAX_RETRY 或 maxRetry
枚举成员 PascalCase OrderStatus.Pending
私有成员 不强制前缀 private userId: number
文件 kebab-case 或 camelCase user-service.ts, userService.ts
// ✅ 类型定义大写开头
interface UserProfile {
  id: number;
  name: string;
}

// ✅ 优先 interface,需要联合类型时用 type
interface ApiResponse<T> { data: T; code: number; }
type Status = 'active' | 'inactive' | 'pending';
1
2
3
4
5
6
7
8
9

# 03.类型与接口

# 3.1 interface 与 type 的选择

// ✅ 定义对象结构:优先 interface
interface User {
  id: number;
  name: string;
  email?: string;
}

// ✅ 联合类型 / 交叉类型 / 映射类型:用 type
type Result<T> = { success: true; data: T } | { success: false; error: string };
type Admin = User & { permissions: string[] };
type ReadonlyUser = Readonly<User>;

// ✅ 函数签名:两者皆可,团队统一即可
type Fn = (x: number) => string;
interface Fn { (x: number): string; }

// ✅ 禁止空的 interface / type
// ❌ interface Empty {}
// ❌ type Empty = {};

// ✅ 类型断言用 as
const el = document.getElementById('app') as HTMLDivElement;
// ❌ 禁止 <Type> 断言(与 JSX 冲突)

// ✅ 声明顺序:static > instance, field > constructor > method, public > protected > private
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 3.2 辨识联合类型(Discriminated Union)【推荐】

// ✅ 用字面量字段作为"标签"来区分联合类型
type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'rectangle'; width: number; height: number }
  | { kind: 'triangle'; base: number; height: number };

function area(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;
  }
  // ✅ TS 会检查 switch 是否覆盖所有分支(exhaustiveness check)
}

// ❌ 反模式:用可选字段区分类型
interface Event {
  type: string;
  userId?: string;     // 只存在于 UserEvent
  orderId?: string;    // 只存在于 OrderEvent
}
// → 调用方不知道哪些字段何时存在
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 3.3 类型收窄(Type Narrowing)【推荐】

// ✅ typeof 收窄
function padLeft(value: string | number, padding: string | number) {
  if (typeof padding === 'number') {
    return ' '.repeat(padding) + value;  // padding 收窄为 number
  }
  return padding + value;                // padding 收窄为 string
}

// ✅ instanceof 收窄
function handleError(err: Error | string) {
  if (err instanceof Error) {
    console.error(err.message);          // err 收窄为 Error
  } else {
    console.error(err);                  // err 收窄为 string
  }
}

// ✅ 自定义类型守卫(is)
function isUser(obj: unknown): obj is User {
  return typeof obj === 'object' && obj !== null && 'id' in obj && 'name' in obj;
}

// ✅ in 操作符收窄
if ('status' in response) {
  // response 收窄为包含 status 的类型
}

// ❌ 避免用 any 强制转换(放弃类型检查)
const data = response as any;           // ❌
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 3.4 satisfies 操作符(TS 4.9+)【推荐】

// ✅ satisfies:既检查类型,又保留字面量推导
const palette = {
  red: [255, 0, 0],
  green: '#00ff00',
  blue: [0, 0, 255],
} satisfies Record<string, string | number[]>;

// ✅ 每个属性的精确类型被保留
palette.red.push(128);      // ✅ 推导为 number[]
palette.green.toUpperCase(); // ✅ 推导为 string

// ✅ 用在路由配置、API 映射等场景
const routes = {
  home: '/',
  user: '/user/:id',
  settings: '/settings',
} satisfies Record<string, string>;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 04.函数规范

# 4.1 参数与返回值类型

function getUser(id: number): Promise<User | null> { return db.users.findUnique({ where: { id } }); }

// ✅ 可选参数用 ?,有默认值时可省略类型标注 function connect(host: string, port = 8080, ssl?: boolean): Connection { // ... }

// ✅ 函数重载:按顺序声明 function parse(input: string): number; function parse(input: string[]): number[]; function parse(input: string | string[]): number | number[] { // 实现 }

// ✅ 优先用联合类型而非同名但参数不同的函数 function log(message: string, level?: 'info' | 'warn' | 'error'): void { ... }


### 4.2 函数重载

```typescript
// ✅ 重载签名在上,实现签名在下(实现签名不对外)
function parse(input: string): number;
function parse(input: string[]): number[];
function parse(input: string | string[]): number | number[] {
  if (typeof input === 'string') return parseInt(input, 10);
  return input.map(s => parseInt(s, 10));
}

// ✅ 字符串模式重载(常用场景)
function createElement(tag: 'a'): HTMLAnchorElement;
function createElement(tag: 'div'): HTMLDivElement;
function createElement(tag: 'img'): HTMLImageElement;
function createElement(tag: string): HTMLElement {
  return document.createElement(tag);
}

// ❌ 重载数量不宜过多(>3 个考虑是否设计有问题)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 4.3 this 参数类型 【推荐】

// ✅ 声明 this 类型(伪参数,编译后擦除)
class Button {
  private disabled = false;

  click(this: Button) {          // 强制 this 为 Button 实例
    if (this.disabled) return;
    // ...
  }
}

// ❌ 如果回调中会丢失 this 绑定,TS 会报错
// button.click.call(null);       // ❌ 编译错误

// ✅ 回调场景
interface UIElement {
  addClickListener(onclick: (this: void, e: Event) => void): void;
  // this: void 表示回调内部不应该使用 this
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 05.类设计规范

// ✅ 使用 ES6 class,避免原型链直接操作
class OrderService {
  // 静态成员在最前
  private static instance: OrderService;

  // 实例字段
  private readonly repository: OrderRepository;

  // 构造函数
  public constructor(repository: OrderRepository) {
    this.repository = repository;
  }

  // 公共方法
  public async create(data: CreateOrderDto): Promise<Order> { ... }

  // 私有方法
  private async validate(data: CreateOrderDto): Promise<boolean> { ... }
}

// ✅ 禁止 this 赋值给临时变量(用箭头函数)
class Timer {
  start() {
    setTimeout(() => {
      this.onTick();   // ✅ 箭头函数自动绑定
    }, 1000);
  }
}

// ❌ 禁止 constructor 参数加修饰符简化声明(保持清晰)
// 建议显式声明字段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 06.导入与模块

// ✅ 用 import 而非 require
import fs from 'fs';
import { join } from 'path';

// ❌ const fs = require('fs');

// ✅ 禁止三斜杠引用
// ❌ /// <reference path="./module" />

// ✅ 导入类型用 import type
import type { User } from './models';
import { createUser, type CreateUserDto } from './service';

// ✅ 导出
export { UserService, type UserConfig };
export default UserService;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 07.空安全与可选链

// ✅ 可选链(?.)
const city = user?.address?.city;

// ✅ 空值合并(??)
const name = user?.name ?? 'Unknown';

// ✅ 非空断言(仅在你确定非空时)
const el = document.getElementById('app')!;

// ❌ 可选链后不跟非空断言
// user?.name!  // 多余
1
2
3
4
5
6
7
8
9
10
11

# 08.泛型使用规范

# 8.1 基础泛型与约束

// ✅ 有意义的泛型名(T, U, K, V 是惯例)
function map<T, U>(items: T[], fn: (item: T) => U): U[] {
  return items.map(fn);
}

// ✅ 泛型约束(extends)
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

// ✅ 泛型默认值
interface Config<T = string> {
  value: T;
  validate(v: T): boolean;
}

// ✅ 泛型工厂函数
function create<T>(Ctor: new (...args: unknown[]) => T, ...args: unknown[]): T {
  return new Ctor(...args);
}

// ❌ 避免不必要的泛型——能被推断就不加
const ids = [1, 2, 3];          // number[] 自动推断,不需要 <number>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 8.2 条件类型与 infer 【推荐】

// ✅ 条件类型:T extends U ? X : Y
type IsString<T> = T extends string ? true : false;
type A = IsString<'hello'>;  // true
type B = IsString<42>;       // false

// ✅ infer:从类型中提取部分
type ReturnType<T> = T extends (...args: unknown[]) => infer R ? R : never;
type UnwrapPromise<T> = T extends Promise<infer V> ? V : T;
type ArrayElement<T> = T extends (infer E)[] ? E : never;

// ✅ 分布式条件类型(联合类型自动分发)
type ToArray<T> = T extends unknown ? T[] : never;
type X = ToArray<string | number>;  // string[] | number[]

// ✅ 实用条件类型示例
type ApiResponse<T> =
  T extends { error: string } ? ErrorResult
  : T extends { data: unknown } ? SuccessResult<T['data']>
  : never;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 8.3 模板字面量类型(TS 4.4+)【推荐】

// ✅ 字符串模式匹配
type EventName = `on${Capitalize<string>}`;
// 'onClick' | 'onChange' | 'onSubmit' | ...

type CSSProperty = 'margin' | 'padding';
type CSSDirection = 'Top' | 'Right' | 'Bottom' | 'Left';
type CSSKey = `${CSSProperty}${CSSDirection}`;
// 'marginTop' | 'marginRight' | ...

// ✅ 路由参数类型安全
type Route = `/user/${string}` | `/post/${number}`;
function navigate(path: Route) { }
navigate('/user/yc');            // ✅
// navigate('/admin/yc');        // ❌ 编译错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 09.枚举与常量

# 10.异步与 Promise

// ✅ Promise 明确返回类型
async function fetchUser(id: number): Promise<User> {
  const res = await fetch(`/api/users/${id}`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  return res.json();
}

// ✅ 条件中 Promise 必须 await
async function check(): Promise<void> {
  // ❌ if (fetchUser(1)) { ... }  // Promise 恒为 truthy
  const user = await fetchUser(1);
  if (user) { ... }
}

// ✅ 并发请求用 Promise.all
const [user, posts] = await Promise.all([
  fetchUser(id),
  fetchPosts(id),
]);

// ✅ 用 try-catch 处理 async 错误
try {
  const data = await riskyOperation();
} catch (error) {
  logger.error('Operation failed', error);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 09.枚举与常量

// ✅ 字符串枚举优于数字枚举
enum OrderStatus {
  Pending = 'pending',
  Paid = 'paid',
  Cancelled = 'cancelled',
}

// ✅ 常量枚举(内联优化)
const enum Direction { Up, Down, Left, Right }

// ✅ 需要常量对象的场景用 const + as const
const STATUS_MAP = {
  pending: '待处理',
  paid: '已支付',
} as const;
type Status = keyof typeof STATUS_MAP;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 11.工具链与自动化

# 11.1 tsconfig 严格模式

{
  "compilerOptions": {
    "strict": true,                          // 开启所有严格检查
    "noImplicitReturns": true,               // 函数所有路径必须返回值
    "noUncheckedIndexedAccess": true,        // 索引访问加 undefined
    "noFallthroughCasesInSwitch": true,      // switch 禁止穿透
    "forceConsistentCasingInFileNames": true,// 文件名大小写一致
    "noUnusedLocals": true,                  // 禁止未用的局部变量
    "noUnusedParameters": true,              // 禁止未用的参数
    "exactOptionalPropertyTypes": true       // 可选属性不能显式赋 undefined
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 11.2 ESLint 与 Prettier

# 安装
npm install -D @typescript-eslint/parser @typescript-eslint/eslint-plugin
1
2
// .eslintrc.js
module.exports = {
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:@typescript-eslint/strict',
  ],
  rules: {
    '@typescript-eslint/no-explicit-any': 'error',
    '@typescript-eslint/consistent-type-imports': 'error',
    '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
    '@typescript-eslint/array-type': ['error', { default: 'generic' }],
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 11.3 CI 集成

# GitHub Actions
- name: Type Check
  run: npx tsc --noEmit                # 仅检查类型,不产出文件

- name: Lint
  run: npx eslint . --ext .ts,.tsx

- name: Test
  run: npx vitest run
1
2
3
4
5
6
7
8
9

# 12.代码审查清单

每次 Code Review 时,按以下清单逐项检查:

## 类型设计
- [ ] 无 any(除非有充分理由 + JSDoc 注释)
- [ ] 公开函数有明确的参数和返回值类型
- [ ] interface / type 无不明确成员
- [ ] 辨识联合的 switch 覆盖所有分支
- [ ] 类型收窄用 is 守卫而非 as 断言

## 命名与结构
- [ ] 变量/函数 camelCase,类/接口/类型 PascalCase
- [ ] 无拼音、无单字母(循环索引除外)
- [ ] 类型导入用 import type

## 安全
- [ ] 可选属性用 ?. 访问,空值用 ??
- [ ] 无不必要的 ! 非空断言
- [ ] async 函数有 try-catch 错误处理
- [ ] 条件中 Promise 必须 await

## 设计原则
- [ ] 优先 interface,联合类型 / 映射类型用 type
- [ ] 无空的 interface / type
- [ ] 泛型有意义的名称和约束
- [ ] 函数重载不超过 3 个签名

## 工程
- [ ] strict: true 无编译错误
- [ ] 无 eslint 告警
- [ ] import 顺序正确(外部→内部→类型)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

# 13.常见陷阱速查

# 13.1 类型陷阱

# 陷阱 正解
1 null 和 undefined 不加检查→运行时 crash 开启 strictNullChecks,或 value ?? fallback
2 as 断言绕过检查→类型不匹配编译通过 用类型守卫 is 收窄代替 as
3 any 污染→传了 any 的地方类型检查全败 用 unknown + 收窄,逐步消除 any
4 enum 编译后产生 JS 对象(有运行时开销) 常量枚举 const enum 或字面量联合类型 'a' \| 'b'
5 可选链后接非空断言 user?.name! 去掉 !,user?.name 足矣

# 13.2 泛型陷阱

# 陷阱 正解
1 泛型不约束→类型信息丢失 加 extends 约束
2 函数泛型过度推断→返回值类型错 显式传入泛型参数 fn<User>(data)
3 条件类型嵌套过深→类型报错不可读 拆成多个具名类型别名
4 用 Function 类型→丢失参数和返回值信息 (...args: unknown[]) => unknown

# 13.3 工程陷阱

# 陷阱 正解
1 skipLibCheck: true 掩盖第三方类型错误 先修类型错误,万不得已再打开
2 @ts-ignore / @ts-expect-error 泛滥 只在真正需要的行用 @ts-expect-error + 注释原因
3 不区分 import type 和普通 import 类型导入用 import type(编译后擦除,无循环依赖风险)
4 tsconfig 不开启 strict→类型系统形同虚设 "strict": true 是底线
5 CI 不做 tsc --noEmit→合并后有类型错误 CI 必须做类型检查 + lint
#TypeScript#代码规范
上次更新: 2026/06/17, 11:39:29
JavaScript编程规范指南
Python编程代码规范指南

← JavaScript编程规范指南 Python编程代码规范指南→

最近更新
01
信号崩溃快速排查
06-15
02
CoreDump破案
06-15
03
perf火焰图实战
06-15
更多文章>
Theme by Vdoing | Copyright © 2019-2026 杨充 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式