TypeScript 中的类基础

本文献给:

已掌握 TypeScript 接口、类实现接口等知识的开发者。本文将带你系统学习 TypeScript 中类的核心语法,包括字段、构造函数、方法、访问修饰符(public/private/protected)、只读属性以及参数属性(构造器简写),为后续继承、多态、抽象类等内容打下基础。

你将学到:

  1. 类的字段、构造函数与方法定义
  2. publicprivateprotected 的区别与使用场景
  3. readonly 只读属性
  4. 参数属性(Parameter Properties)简化代码
  5. 类的类型注解与实例化

目录

  • 一、类的定义
    • [1.1 基本语法](#1.1 基本语法)
    • [1.2 字段初始化](#1.2 字段初始化)
  • 二、访问修饰符
    • [2.1 public(默认)](#2.1 public(默认))
    • [2.2 private](#2.2 private)
    • [2.3 protected](#2.3 protected)
  • [三、readonly 只读属性](#三、readonly 只读属性)
  • [四、参数属性(Parameter Properties)](#四、参数属性(Parameter Properties))
    • [4.1 传统写法 vs 参数属性](#4.1 传统写法 vs 参数属性)
    • [4.2 可与其他修饰符组合](#4.2 可与其他修饰符组合)
  • 五、类作为类型
  • 六、常见错误与注意事项
    • [6.1 未初始化的属性](#6.1 未初始化的属性)
    • [6.2 `private` 与 `#` 混淆](#` 混淆)
    • [6.3 参数属性顺序](#6.3 参数属性顺序)
    • [6.4 子类访问 `protected` 成员](#6.4 子类访问 protected 成员)
    • [6.5 类类型与实例类型](#6.5 类类型与实例类型)
  • 七、综合示例
  • 八、小结

一、类的定义

TypeScript 的类在 ES6 类语法的基础上增加了类型注解和访问修饰符。

1.1 基本语法

typescript 复制代码
class Person {
    name: string;
    age: number;
    
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
    
    greet(): string {
        return `Hello, I'm ${this.name}`;
    }
}

const alice = new Person("Alice", 25);
console.log(alice.greet());

1.2 字段初始化

字段可以在声明时赋初始值。

typescript 复制代码
class Counter {
    count: number = 0;
    label: string = "Counter";
    
    increment() {
        this.count++;
    }
}

二、访问修饰符

TypeScript 提供了三种访问修饰符,控制类成员的可见性。

2.1 public(默认)

如果不写修饰符,成员默认为 public,可以在任何地方访问。

typescript 复制代码
class Animal {
    public name: string;
    public constructor(name: string) {
        this.name = name;
    }
    public speak() {
        console.log(`${this.name} makes a sound`);
    }
}

const a = new Animal("Dog");
console.log(a.name);  // 外部可访问
a.speak();

2.2 private

private 成员只能在类内部访问,不能在子类或外部访问。

typescript 复制代码
class BankAccount {
    private balance: number = 0;
    
    deposit(amount: number) {
        this.balance += amount;
    }
    
    getBalance() {
        return this.balance;
    }
}

const account = new BankAccount();
account.deposit(100);
// console.log(account.balance);  // ❌ 私有属性,外部不可访问
console.log(account.getBalance()); // 100

TypeScript 的 private 是编译时检查,编译后的 JavaScript 中并没有真正的私有字段(除非使用 ES2022 的 # 私有字段)。如果希望运行时的真正私有,可以使用 #

typescript 复制代码
class WithHashPrivate {
    #secret = 42;
    reveal() {
        return this.#secret;
    }
}

2.3 protected

protected 成员可以在类内部和子类中访问,但不能在外部访问。

typescript 复制代码
class Parent {
    protected value: string = "protected";
}

class Child extends Parent {
    show() {
        console.log(this.value);  // ✅ 子类可访问
    }
}

const c = new Child();
c.show();
// console.log(c.value);  // ❌ 外部不可访问

三、readonly 只读属性

readonly 修饰符让属性只能在声明时或构造函数中被赋值,之后不可修改。

typescript 复制代码
class Config {
    readonly appName: string;
    readonly version: string = "1.0.0";
    
    constructor(appName: string) {
        this.appName = appName;  // 构造函数中赋值允许
    }
    
    changeName() {
        // this.appName = "New";  // ❌ 不可修改
    }
}

const cfg = new Config("MyApp");
console.log(cfg.appName);
// cfg.appName = "Other";  // ❌

readonly 与访问修饰符可以同时使用,通常写在修饰符后面:

typescript 复制代码
class Example {
    public readonly id: number;
    protected readonly createdAt: Date;
    private readonly secret: string;
    
    constructor(id: number, secret: string) {
        this.id = id;
        this.createdAt = new Date();
        this.secret = secret;
    }
}

四、参数属性(Parameter Properties)

TypeScript 提供了一种简写方式,可以在构造函数参数中直接声明并初始化类属性。在参数前加上访问修饰符或 readonly,TypeScript 会自动创建同名字段并赋值。

4.1 传统写法 vs 参数属性

typescript 复制代码
// 传统写法
class UserOld {
    name: string;
    age: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    }
}

// 参数属性写法
class User {
    constructor(public name: string, public age: number) {}
}

const u = new User("Alice", 25);
console.log(u.name);  // "Alice"

4.2 可与其他修饰符组合

typescript 复制代码
class Service {
    constructor(
        private readonly apiUrl: string,
        protected timeout: number,
        public debug: boolean = false
    ) {}
}

参数属性大大简化了代码,是 TypeScript 类中的常见模式。

五、类作为类型

在 TypeScript 中,类同时创建了两个东西 :一个 (构造函数,在运行时存在)和一个类型(实例的类型,在编译时存在)。

typescript 复制代码
class Point {
    x: number = 0;
    y: number = 0;
}

// 作为类型
const p1: Point = new Point();

// 作为值
const PointClass = Point;  // 将构造函数赋给变量
const p2 = new PointClass();

因此,类可以像接口一样用于类型注解。

typescript 复制代码
function printPoint(p: Point) {
    console.log(p.x, p.y);
}

六、常见错误与注意事项

6.1 未初始化的属性

如果属性没有初始值,也不在构造函数中赋值,TypeScript(在严格模式下)会报错。

typescript 复制代码
class MyClass {
    field: string;  // ❌ 属性未初始化
}

解决方法:赋初始值、构造函数中赋值,或使用非空断言 !(不推荐)。

typescript 复制代码
class MyClass {
    field!: string;  // 明确断言会初始化
}

6.2 private# 混淆

TypeScript 的 private 只提供编译时检查,编译后是普通属性。真正的运行时私有字段使用 #

typescript 复制代码
class C {
    private x = 0;
    #y = 0;
}
// 编译后,x 变成 this.x,仍然可访问;#y 会转为 WeakMap 或使用原生私有字段

6.3 参数属性顺序

参数属性必须放在构造函数参数的最前面(或与普通参数混用时没有严格顺序要求,但通常建议集中放在前面或后面)。使用参数属性后,不能再显式写 this.xxx = xxx

6.4 子类访问 protected 成员

子类只能通过自身实例访问 protected 成员,不能通过父类实例访问。

typescript 复制代码
class Parent {
    protected value = 42;
}
class Child extends Parent {
    tryAccess(parent: Parent, child: Child) {
        console.log(this.value);     // OK
        console.log(child.value);    // OK
        // console.log(parent.value); // ❌ 不能通过父类实例访问
    }
}

6.5 类类型与实例类型

类名作为类型时,指的是实例的类型,不是构造函数类型。要获取构造函数类型,使用 typeof MyClass

typescript 复制代码
const ctor: typeof MyClass = MyClass;

七、综合示例

typescript 复制代码
// 定义一个用户类
class User {
    // 参数属性 + 只读
    constructor(
        public readonly id: number,
        public name: string,
        private email: string,
        protected role: string = "user"
    ) {}
    
    // 方法
    getEmail(): string {
        return this.email;
    }
    
    setEmail(newEmail: string) {
        // 简单验证
        if (newEmail.includes("@")) {
            this.email = newEmail;
        } else {
            console.log("Invalid email");
        }
    }
    
    describe(): string {
        return `${this.name} (${this.role})`;
    }
}

// 子类
class Admin extends User {
    private permissions: string[];
    
    constructor(id: number, name: string, email: string) {
        super(id, name, email, "admin");
        this.permissions = ["read", "write", "delete"];
    }
    
    listPermissions() {
        console.log(this.permissions);
    }
    
    // 可以访问 protected 成员 role
    getRole(): string {
        return this.role;
    }
}

// 使用
const user = new User(1, "Alice", "alice@example.com");
console.log(user.id);          // 1
console.log(user.name);        // "Alice"
// console.log(user.email);    // ❌ private
console.log(user.getEmail());  // "alice@example.com"
user.setEmail("new@example.com");

const admin = new Admin(2, "Bob", "bob@admin.com");
admin.listPermissions();
console.log(admin.getRole());  // "admin"

// 类作为类型
function printUserInfo(u: User) {
    console.log(u.describe());
}
printUserInfo(user);
printUserInfo(admin);  // 子类实例也可传入

// 获取构造函数类型
type UserConstructor = typeof User;
const AnotherUser: UserConstructor = User;
const u2 = new AnotherUser(3, "Charlie", "charlie@example.com");

八、小结

概念 语法示例 说明
字段声明 name: string; 定义实例属性
构造函数 constructor(...) {} 初始化实例
方法 greet() {} 实例方法
public public name: string 默认修饰符,任何地方可访问
private private secret: string 仅类内部可访问
protected protected value: number 类内部及子类可访问
readonly readonly id: number 只读,不可修改
参数属性 constructor(public name: string) {} 简写声明并赋值
类作为类型 let p: MyClass = new MyClass() 类名表示实例类型

觉得文章有帮助?别忘了:

👍 点赞 👍 -- 给我一点鼓励
⭐ 收藏 ⭐ -- 方便以后查看
🔔 关注 🔔 -- 获取更新通知


标签: #TypeScript #类 #构造函数 #访问修饰符 #学习笔记 #前端开发

相关推荐
mCell2 小时前
从云相册的缩略图说起:Bun.Image 让我告别 sharp
javascript·图片资源·bun
ljt27249606613 小时前
Vue笔记(三)--用户交互
javascript·vue.js·笔记
Martin -Tang3 小时前
uniapp 实现录音操作,长按录音,放开取消
前端·javascript·vue.js·uni-app·css3·录音
ZC跨境爬虫3 小时前
跟着 MDN 学 HTML day_58:(构建行星数据表——HTML表格高级实战指南)
前端·javascript·ui·html·音视频
kyriewen3 小时前
用户打开飞行模式都能打开你的网站?Service Worker 做离线缓存,PWA 实战
前端·javascript·面试
栉甜3 小时前
APIs学习
前端·javascript·css·学习·html
缘友一世4 小时前
Ubuntu24安装Steam客户端NVIDIA 显卡驱动异常:从诊断到修复的全过程
ubuntu·steam·nvidia drive
zithern_juejin4 小时前
ES6——Symbol
javascript
代码煮茶4 小时前
Vue3 组件库二次封装实战 | 基于 Element Plus 封装企业级 UI 组件库
前端·javascript·vue.js