TS 相关

TS & JS 区别?

ts 是 js 的超集

  • 特性
    1. 类型批注
    2. 编译时类型检查
    3. 类型推断
    4. 类型擦除
    5. 泛型编程

type

1. 原始类型的别名

ini 复制代码
type ID = number;
type Name = string;
type IsActive = boolean;

const userId: ID = 123;
const userName: Name = "Alice";

2. 对象类型的别名

ini 复制代码
type User = {
  id: number;
  name: string;
  email?: string;
};
const user: User = {
  id: 1,
  name: "Bob"
};

3. 联合类型(Union Types)

满足多个类型中的任意一个类型,"或" T | U

ini 复制代码
type Status = "active" | "inactive" | "pending";
type ID = number | string;

const status: Status = "active"; // 必须是其中之一
const userId: ID = "abc123";     // 可以是 number 或 string

用于限制值的范围,实现类型安全的枚举式字段。

  • 获取联合类型的key 1,取值
ts 复制代码
enum Direction {
  left,
  top,
  right = 20,
  bottom
}
type D = keyof typeof Direction // type D = "left" | "top" | "right" | "bottom"
  • 获取联合类型的key 2, 使用 keyof + 联合类型
ini 复制代码
type User = { id: number; name: string }
type Product = { id: number; price: number }
type Data = User | Product

// 获取所有可能的 key
type Keys1 = keyof Data
// 等价于:
type Keys2 = keyof User | keyof Product
// 等价于:
type Keys3 = keyof (User | Product)

4. 交叉类型(Intersection Types)

将多个类型合并为一个类型,"并" T & U

ini 复制代码
type Name = {
  name: string;
};
type Age = {
  age: number;
};
type Person = Name & Age;
const person: Person = {
  name: "Charlie",
  age: 25
};

将多个类型合并为一个,所有字段都必须存在

5. 元组类型(Tuple)

ts 复制代码
type Coordinates = [string, number];
type RGB = [number, string, number];

const point: Coordinates = ['sss', 20];
const color: RGB = [255, 'dasd', 0];

6. 函数类型

typescript 复制代码
type GreetFunction = (name: string) => string;
const greet: GreetFunction = (name) => `Hello, ${name}`;

7. 泛型类型别名

css 复制代码
type Box<T> = {
  value: T;
};
const stringBox: Box<string> = { value: "hello" };
const numberBox: Box<number> = { value: 42 };

8. 类型别名

使用 type 关键字为一个类型起一个"别名"。 type 别名 = 类型定义

typescript 复制代码
type T = string | number // T 为类型别名

interface

interface(接口)是定义对象结构的核心机制之一。用于描述对象的形状(shape),包括属性、方法、索引签名等。

typescript 复制代码
interface Animal {
  readonly name: string
  age: number | null
  sex?: string
  set: (key: string, val: string | number) => void  // ✅ 方法签名
  get?: () => string                                // ✅ 函数类型接口
  speak(): void
  eat?(food: string): string
}

interface 继承

ts 复制代码
interface Animal {
  sex?: string
  say: () => void
}
interface Person {
  name: string
  age: number | null
}
interface Dog extends Animal, Person {
  height: string
}
const d: Dog = {} // ❌ 错误,类型"{}"缺少类型"Dog"中的以下属性: height, say, name, age

混合接口(同时有属性和方法)

ts 复制代码
interface Couter {
  (start: string): string
  interval: number
  reset(): void
}
const initCouter = function (start: string) {
  return start + ''
} as Couter

initCouter.interval = 1000
initCouter.reset = () => {
  /* ... */
}}

interface 和 type 区别

interface vs type

特性 interface type
定义对象结构 ✅ 推荐
支持继承 extends ✅ 使用交叉类型 &
支持声明合并
可定义联合类型
可定义元组、函数类型
可用于条件类型
扩展性 更好(适合长期演进) 固定定义
  • 优先使用 interface 描述对象和类的结构。
  • 使用 type 定义联合类型、复杂类型、映射类型等。

Class 类

class(类)是面向对象编程的核心,它在 JavaScript 的 class 基础上增加了 类型注解、访问修饰符、抽象类、静态类型检查 等特性

基本使用

ts 复制代码
class Person {
  public name: string
  protected age: number
  protected sex?: string
  private address?: string
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
  say(): string {
    const d = `Hello, 我是 ${this.name}, 今年${this.age}岁`
    return d
  }
}
const person = new Person('Rubin', 25)
person.say() // ✅ "Hello, 我是Rubin, 今年25岁"
Person.sex   // ❌ 错误,类型"typeof Person"上不存在属性"sex"。
Person.age   // ❌ 错误,类型"typeof Person"上不存在属性"age"。

类的初始参数简写

ts 复制代码
class Person {
  constructor(public readonly name: string, private age: number) { }
}
const p = new Person('runbin', 33)
p.name
p.age // ❌ 

类的继承

typescript 复制代码
class Person {
  public name: string
  protected age: number
  protected sex?: string
  constructor(name: string, age: number, sex: string) {
    this.name = name
    this.age = age
    this.sex = sex
  }
  say(): string {
    const d = `Hello, 我是 ${this.name}, 今年${this.age}岁`
    return d
  }
}
class Father extends Person {
  height: number
  constructor(name: string, age: number, height: number) {
    super(name, age) // 调用父类构造函数
    this.height = height
  }
  say(): string {
    super.say()
    const d = `Hello, 我是 ${this.name}, 今年${this.age}岁,性别` + this.sex
    return d
  }
}
const father = new Father('Rubin', 25, 188, '男')
father.say() // ✅ "Hello, 我是Rubin, 今年25岁,性别男"

修饰符 public private protected readonly

类属性修饰符(Class Property Modifiers)用于控制类成员(属性和方法)的访问权限、行为和类型。它们是实现封装、继承和类型安全的重要工具。

  1. public 可以在类内部、子类、外部实例中访问。
  2. private 只能在定义它的类内部访问,子类和外部实例都不能访问。
  3. protected 类内部 + 子类中可访问,外部实例不能访问。
  4. readonly 只读,属性只能在声明时或构造函数中初始化,之后不能修改。
  5. static - 静态,属于类本身 ,不属于任何实例。通过 类名.属性 访问,不能通过 this 或实例访问。
ts 复制代码
class Person {
  public name: string
  protected age: number
  protected sex?: string
  private readonly address = '北京'
  static P1 = 'P1P1P1'
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}
const person = new Person('小明', 19)
person.name   // ✅
Person.name   // ✅
Person.age    // ❌ 错误,类型"typeof Person"上不存在属性"age"。
Person.sex    // ❌ 错误,类型"typeof Person"上不存在属性"sex"。
person.P1     // ✅
Person.P1     // ❌ 错误,属性"P1"在类型"Person"上不存在

类新的私有属性提案:"#属性"

ts 复制代码
class Person {
  #address = '北京'
}

const p = new Person()
p['#address'] // ❌ 错误,类型"Person"上不存在属性"#address"

抽象类

abstract(抽象)是一个关键字,用于定义 抽象类(Abstract Class)抽象方法(Abstract Method) 。它用于创建只能被继承、不能被直接实例化的基类,常用于面向对象编程中定义接口契约和共享逻辑。

ts 复制代码
abstract class Animal {
    abstract say(): void
}
// ❌ 子类如不实现say函数,就报错:非抽象类"Person"不会实现继承自"Animal"类的抽象成员 say。
class Person extends Animal {
  nosay() {
    console.log(';abstract')
  }
}

基础类型

1. string 类型 - 字符串

ts 复制代码
let userName: string = "Alice";
let greeting: string = `Hello, ${userName}!`;
console.log(greeting); // 输出: Hello, Alice!

2. number 类型 - 数字(整数、浮点数、NaN、Infinity)

ts 复制代码
let age: number = 25;
let price: number = 99.99;
let score: number = NaN;
let bigNumber: number = Infinity;
console.log(age, price, score, bigNumber);

3. boolean 类型 - 布尔值

ts 复制代码
let isActive: boolean = true;
let isLoggedIn: boolean = false;
console.log(isActive); // true

4. null 类型 - 空值

ts 复制代码
let car: string | null = null; // 注意:null 通常与联合类型一起使用
car = "Toyota";
console.log(car);

5. undefined 类型 - 未定义

ts 复制代码
let user: { name?: string } = {};
let nickname: string | undefined = user.name;
console.log(nickname); // undefined

6. symbol 类型 - 唯一标识符(ES6)

ts 复制代码
const id1: symbol = Symbol("id");
const id2: symbol = Symbol("id");
console.log(id1 === id2); // false(每个 symbol 都是唯一的)

7. bigint 类型 - 大整数(ES2020)

ts 复制代码
const bigInt2: bigint = BigInt(456);
console.log(bigInt1 + bigInt2); // 579n

8. any 类型 - 任意类型(不推荐滥用)

ts 复制代码
let anything: any = "hello";
anything = 100;
anything = true;
console.log(anything); // true

9. unknown 类型 - 未知类型(比 any 更安全)

ts 复制代码
let userInput: unknown = "hello";
userInput = 10;
// 必须进行类型检查才能使用
if (typeof userInput === "number") {
  console.log(userInput * 2);
} else {
  console.log("Not a number");
}

10. void 类型 - 无返回值

ts 复制代码
function logMessage(message: string): void {
  console.log(message);
}
logMessage("This function returns nothing.");

11. never 类型 - 永不返回(如抛出异常或死循环)

ts 复制代码
function throwError(message: string): never {
  throw new Error(message);
}
// function infiniteLoop(): never {
//   while (true) {}
// }

12. 字面量类型 - 精确值

ts 复制代码
type Direction = "left" | "right" | "up" | "down";
let move: Direction = "left";
// move = "forward"; // ❌ 错误:不在允许范围内

type StatusCode = 200 | 404 | 500;
let status: StatusCode = 200;

13. 数组类型

ts 复制代码
let numbers: number[] = [1, 2, 3];
let names: Array<string> = ["Alice", "Bob"];

14. 元组类型 - 固定长度和类型的数组

ts 复制代码
let person: [string, number] = ["Charlie", 30];
console.log(person[0]); // "Charlie"
console.log(person[1]); // 30

15. 枚举类型(enum)

ts 复制代码
enum Color {
  Red = "RED",
  Green = "GREEN",
  Blue = "BLUE",
}
let favoriteColor: Color = Color.Green;
console.log(favoriteColor); // "GREEN"
  • 数字枚举
ts 复制代码
enum Direction {
  left,
  top,
  right = 20,
  bottom
}
const left = Direction.left           // 0
const top = Direction.top             // 1
const right = Direction.right         // 20
const bottom = Direction.bottom       // 21
console.log(left, top, right, bottom) // ✅ 0 1 20 21
  • 异构枚举
ts 复制代码
enum WR {
  no = 100,
  yes = "yes"
}
const no = WR.no       // 100
const yes = WR.yes     // "yes"
console.log(no, yes)   // ✅ 100, "yes"

16. 类型推断(Type Inference)

ts 复制代码
let country = "China"; // 自动推断为 string
let temperature = 25.5; // 自动推断为 number
let isLoading = true;   // 自动推断为 boolean

17. 使用 typeof 获取值的类型(在类型层面)

js 复制代码
const userObj = { name: "David", age: 28 };
type User = typeof userObj;
// 等价于: type User = { name: string; age: number; }

const user2: User = { name: "Eve", age: 22 };
console.log(user2);

高级类型

1. keyof 获取对象类型的键名

keyof 获取所有键的联合。

ts 复制代码
type User = {
  id: number;
  name: string;
  email: string;
};
// 获取所有键的联合类型
type UserKeys = keyof User; // 结果:UserKeys 是 "id" | "name" | "email" 

用法:类型索引

ts 复制代码
function getInfo<User>(user: User, key: keyof User) {
  return user[key]
}
getInfo({ name: 'B', age: 2 }, 'age') // ✅ OK
getInfo({ name: 'A', age: 1 }, 'ccc') // ❌ 错误,类型"ccc"的参数不能赋给类型"age"|"name"的参数

2. typeof 从值推导类型

ini 复制代码
const user = {
  name: "Alice",
  age: 30
};

// 使用 typeof 获取 user 的结构类型
type UserType = typeof user;
// 等价于:
type UserType = {
  name: string;
  age: number;
}
const newUser: UserType = {
  name: "Bob",
  age: 25
};

用法:从配置对象自动推导类型

ts 复制代码
const config = {
  apiUrl: "https://api.example.com",
  timeout: 5000,
  withCredentials: true
};
type Config = typeof config;
function request<T>(url: string, options: Config): Promise<T> {
  // ...
}

用法:联合类型判断(类型守卫)

ts 复制代码
if (typeof value === "string") {
   console.log(value.toUpperCase()); // TS 知道此时 value 是 string
}

3.类型约束

类型约束(Type Constraints) 是指通过 extends 关键字限制泛型(T, K 等)的取值范围,确保泛型只能是某些特定类型的子集。

ts 复制代码
function get<T extends string | number>(arg: T): T {
  return arg;
}
get("hello"); // ✅ OK
get(42);      // ✅ OK
get(true);    // ❌ 错误,boolean 不在约束范围内

用法:类型约束 + 类型索引

ts 复制代码
function getDate<O, K extends keyof O>(user: O, key: K): O[K] {
  return user[key]
}
getDate({ name: 'ff', age: 1 }, 'name') // ✅ OK
getDate({ name: 'ld', age: 1 }, 'work') // ❌ 错误,类型"work"的参数不能赋给类型"age"|"name"的参数

4.映射类型

类型映射(Mapped Types) 是一种强大的特性,它允许你基于一个已有的类型,通过遍历其属性并应用变换,生成一个新的类型

键名重映射(as)

键名重映射(Key Remapping using as 是映射类型的一个强大新特性。它允许你在定义映射类型时,动态地修改生成的属性名 ,而不仅仅是继承原类型的键。如:驼峰转蛇形、添加前缀、过滤属性、类型驱动的 API 映射 等高级功能。

用法:所有属性变为只读/解除只读/可选/必选

ini 复制代码
type Readonly<T> = {
  // readonly [P in keyof T]: T[P]   // ✅ 所有属性变为**只读**
  // -readonly [P in keyof T]: T[P]  // ✅ 所有属性变为**非只读**
  // [P in keyof T]?: T[P]           // ✅ 都变为**可选**属性
  // [P in keyof T]-?: T[P]          // ✅ 都变为**必选**属性
  // [P in keyof T]: T[P] | null     // ✅ 所有属性变为**可空**
}
type User = { name: string; age: number }
type ReadonlyUser = Readonly<User>

let data: ReadonlyUser = { name: 'string', age: 22 }
data.age = 2    // ❌ 错误,无法为"age"赋值,因为它是只读属性。

用法 1:深度只读

ts 复制代码
type DeepReadonly<T> = {
  readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K]
}
type User = { name: string; age: number; address: { first: string; second: string } }
type DeepReadonlyUser = DeepReadonly<User>

const data: DeepReadonlyUser = { name: 'string', age: 22, address: { f: '北京', s: '海淀' } }
data.address.s = 2 // ❌ 错误,无法为"second"赋值,因为它是只读属性。

用法 2:Pick<T, K>:从 T 中挑选部分属性

ts 复制代码
type User = {
  id: number
  name: string
  email: string
}
type Pick<T, K extends keyof T> = {
  [P in K]: T[P]
}
type UserNameOnly = Pick<User, 'name'>

用法 3:Record<K, T>:创建键为 K、值为 T 的对象

ts 复制代码
type Record<K extends keyof any, T> = {
  [P in K]: T
}
// -------例子 1
type Person = Record<string, string>
const xiaoming1: Person = { name: '小明' }  // ✅ OK
const xiaoming2: Person = { age: 22 }      // ❌ 错误,不能将类型"number"分配给类型"string"。
// -------例子 2
type Keys = 'base' | 'job'
type Info = Record<Keys, { [key: string]: string | number | string[] }>
const data: Info = {
  base: {
    name: 'rubin',
    age: 22
  },
  job: {
    address: '海淀',
    list: ['IT', '超越'],
    title: false  // ❌ 错误,不能将类型"boolean"分配给类型"string | number | string[]"
  },
  sex: 2222  // ❌ 错误,对象字面量只能指定已知属性,并且"sex"不在类型"Info"中。
}

用法 4:PickFnNames<T, K>:提取函数名

ts 复制代码
type PickFnNames<T> = {
  [K in keyof T]: T[K] extends typeof Function ? K : never
}
type Actions = {
  get: () => string
  set: () => void
  val: string
}
type Fns = PickFnNames<Actions>  // 'get' | 'set'

用法 5:过滤属性,只保留字符串类型

ts 复制代码
type OnlyString<T> = {
  [K in keyof T as T[K] extends string ? K : never]: T[K]
}
type User = {
  get: () => string
  age: number
  val: string
}
const data: OnlyString<User> = {
  val: 'woshi',   // ✅ OK
  get: () => { }, // ❌ 错误,对象字面量只能指定已知属性,并且"get"不在类型"OnlyString<User>"中。
  age: 2,         // ❌ 错误,对象字面量只能指定已知属性,并且"age"不在类型"OnlyString<User>"中。
}

用法 6:排除某些属性(实现 Omit 的新方式)

ts 复制代码
type Omit<T, P> = {
  [K in keyof T as K extends P ? never : K]: T[K]
}
type User = {
  name: string
  age: number
}
const data: Omit<User, 'name'> = {
  name: 'woshi', // ❌ 错误,对象字面量只能指定已知属性,并且"name"不在类型"Omit<User, "name">"中。
  age: 22        // ✅ OK
}

工具类型 Exclude Omit Merge Intersection Overwrite

泛型

declear / declear global

declare 用于 声明变量、函数、类、模块或类型 ,但不提供实现。它告诉 TypeScript 编译器:"这个东西在运行时是存在的,你不用管它是怎么来的,请允许我在类型层面使用它。"

它只生成类型信息,不会生成任何 JavaScript 代码。

1. declear 声明一个全局变量/全局函数

ts 复制代码
// 声明一个全局变量
declare const ENV: string;
declare const VERSION: number;
declare const DEBUG: boolean;
// 声明全局函数(Global Functions)
declare function alert(message: string): void;
declare function $(selector: string): any; // jQuery

console.log(ENV); // ✅ 不报错

2. declare namespace 声明命名空间或模块(.d.ts 文件)

.d.ts 类型声明文件中常见:

ts 复制代码
// utils.d.ts
declare namespace MyUtils {
  function capitalize(str: string): string;
  function slugify(str: string): string;
}
// 使用
MyUtils.capitalize("hello"); // ✅ 类型检查通过

3. declare global 扩展全局对象(如 windowNodeJS

ts 复制代码
// 扩展 window 对象
declare global {
  interface Window {
    myname: string
  }
}
Window.myname // ✅ 不报错
typescript 复制代码
// 扩展 Node.js 的 process
declare namespace NodeJS {
  interface ProcessEnv {
    NODE_ENV: 'development' | 'production';
    PORT: string;
  }
}
// 使用
process.env.NODE_ENV; // ✅ 类型安全
相关推荐
烛阴16 分钟前
掌握 TypeScript 的边界:any, unknown, void, never 的正确用法与陷阱
前端·javascript·typescript
前端工作日常2 小时前
H5 实时摄像头 + 麦克风:完整可运行 Demo 与深度拆解
前端·javascript
韩沛晓2 小时前
uniapp跨域怎么解决
前端·javascript·uni-app
拾光拾趣录4 小时前
JavaScript 究竟怎么跑
前端·javascript
Aotman_4 小时前
el-input 重写带图标密码框(点击小眼睛显示、隐藏密码)
前端·javascript·vue.js
神笔码农nice4 小时前
Promise详解:Promise解决ajax回调嵌套问题
前端·javascript
程序员二师兄4 小时前
记一次鸿蒙webview图片渲染失败的问题
前端·javascript·harmonyos
萌萌哒草头将军4 小时前
字节也在用的 @tanstack/react-query 到底有多好用!🔥🔥🔥
前端·javascript·react.js
JohnYan4 小时前
工作笔记 - 改进的单例应用
javascript·设计模式·bun