TypeScript: Classe do TypeScript (class)
Última atualização: 2026-08-26
As classes são um recurso de sintaxe orientado a objetos introduzido no JavaScript ES6. O TypeScript se baseia nisso ao adicionar anotações de tipo e controle de acesso — garantindo que as propriedades e os métodos das classes sejam restritos por tipo.
1. Sintaxe básica das classes
(1) Declarações de propriedades e construtores
O TypeScript exige que as propriedades das classes sejam declaradas antes de poderem ser utilizadas — ao contrário do JavaScript:
class User {
// Property Declaration(TypeScript Requirements)
name: string;
age: number;
// Constructor
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
// Methods
greet(): string {
return `Hello,I am${this.name},This year${this.age} years old`;
}
}
let user = new User("Charlie", 20);
console.log(user.greet()); // "Hello,I amCharlie,This year20 years old"
(2) Várias maneiras de inicializar propriedades
class Config {
// Method 1:Initialize directly upon declaration
host: string = "localhost";
port: number = 3000;
// Method 2:Initialization in the Constructor
env: string;
constructor(env: string) {
this.env = env;
}
// Method 3:Assert that it is not empty(!)——You promise to assign a value later.
data!: string;
}
let cfg = new Config("development");
cfg.data = "some data"; // Create First, Then Assign
!, mas certifique-se de que a propriedade realmente receba um valor.
2. Modificadores de acesso
Os três modificadores de acesso do TypeScript controlam a visibilidade das propriedades e dos métodos:
| Modificador | Dentro da classe | Subclasse | Fora da classe |
|---|---|---|---|
public |
✅ | ✅ | ✅ |
protected |
✅ | ✅ | ❌ |
private |
✅ | ❌ | ❌ |
(1) público (padrão)
class Person {
public name: string; // public This is the default value.,Optional
public age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
let p = new Person("Charlie", 20);
console.log(p.name); // ✅ Accessible from outside the class
p.name = "Diana"; // ✅ Can be modified from outside the class
(2) privado
class BankAccount {
private balance: number;
constructor(initialBalance: number) {
this.balance = initialBalance;
}
public deposit(amount: number): void {
if (amount > 0) this.balance += amount;
}
public withdraw(amount: number): boolean {
if (amount > 0 && amount <= this.balance) {
this.balance -= amount;
return true;
}
return false;
}
public getBalance(): number {
return this.balance;
}
}
let account = new BankAccount(1000);
account.deposit(500);
account.withdraw(200);
console.log(account.getBalance()); // 1300
// account.balance; // ❌ private The property is not accessible from outside
// account.balance = 99999; // ❌ private Properties cannot be modified externally
(3) protegido
class Animal {
protected name: string;
constructor(name: string) {
this.name = name;
}
protected makeSound(sound: string): void {
console.log(`${this.name}:${sound}`);
}
}
class Dog extends Animal {
constructor(name: string) {
super(name);
}
public bark(): void {
this.makeSound("Woof!"); // ✅ Subclasses can access protected Methods
// console.log(this.name); // ✅ Subclasses can access protected Properties
}
}
let dog = new Dog("Wangcai");
dog.bark(); // "Wangcai:Woof!"
// dog.name; // ❌ protected The property is not accessible from outside
// dog.makeSound("Howl"); // ❌ protected This method cannot be called from outside the class.
(4) Notação abreviada para parâmetros de construtor
O TypeScript oferece propriedades de parâmetro — ao adicionar modificadores antes dos parâmetros do construtor, ele declara e inicializa automaticamente as propriedades:
// Complete Syntax
class User1 {
public name: string;
private age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
// Abbreviation——The effect is exactly the same
class User2 {
constructor(
public name: string,
private age: number
) {}
}
let u = new User2("Charlie", 20);
console.log(u.name); // ✅ public
// console.log(u.age); // ❌ private
3. Modificador readonly
readonly Propriedades com modificadores só podem receber valores no momento da declaração ou no construtor:
class Circle {
readonly radius: number;
constructor(radius: number) {
this.radius = radius; // ✅ You can assign values in the constructor
}
get area(): number {
return Math.PI * this.radius ** 2;
}
}
let circle = new Circle(5);
console.log(circle.area); // 78.54
// circle.radius = 10; // ❌ readonly Properties cannot be modified
(1) Propriedades readonly + parâmetros
class Config {
constructor(
readonly host: string,
readonly port: number
) {}
}
let cfg = new Config("localhost", 3000);
console.log(`${cfg.host}:${cfg.port}`); // "localhost:3000"
// cfg.host = "other"; // ❌ readonly
4. Acessadores (getters / setters)
Os acessadores permitem que você execute uma lógica personalizada ao ler ou gravar propriedades:
(1) Sintaxe básica
class Employee {
private _salary: number = 0;
// getter——Execute on read
get salary(): number {
return this._salary;
}
// setter——Perform validation during assignment
set salary(value: number) {
if (value < 0) {
throw new Error("Salaries cannot be negative.");
}
this._salary = value;
}
}
let emp = new Employee();
emp.salary = 8000; // Call setter
console.log(emp.salary); // Call getter → 8000
// emp.salary = -100; // ❌ Throw an error
(2) Propriedades somente leitura (com um getter, mas sem setter)
class User {
constructor(
private firstName: string,
private lastName: string
) {}
get fullName(): string {
return `${this.firstName} ${this.lastName}`;
}
// None setter → fullName It is read-only.
}
let user = new User("San", "Zhang");
console.log(user.fullName); // "San Zhang"
// user.fullName = "Si Li"; // ❌ None setter
▶ Exemplo: Conversor de temperatura
class Temperature {
private _celsius: number = 0;
constructor(celsius: number) {
this._celsius = celsius;
}
get celsius(): number {
return this._celsius;
}
set celsius(value: number) {
if (value < -273.15) {
throw new Error("The temperature must not fall below absolute zero.(-273.15°C)");
}
this._celsius = value;
}
get fahrenheit(): number {
return this._celsius * 9 / 5 + 32;
}
set fahrenheit(value: number) {
this.celsius = (value - 32) * 5 / 9; // Reuse celsius Verification of
}
}
let temp = new Temperature(100);
console.log(`${temp.celsius}°C = ${temp.fahrenheit}°F`); // "100°C = 212°F"
temp.fahrenheit = 32;
console.log(`${temp.celsius}°C = ${temp.fahrenheit}°F`); // "0°C = 32°F"
Saída:
100°C = 212°F
0°C = 32°F
5. Membros estáticos
static As propriedades e métodos modificados pertencem à própria classe, e não à instância:
(1) Propriedades e métodos estáticos
class MathUtils {
static PI: number = 3.14159;
static circleArea(radius: number): number {
return MathUtils.PI * radius ** 2;
}
static clamp(value: number, min: number, max: number): number {
return Math.min(Math.max(value, min), max);
}
}
// No need to create an instance,Call directly using the class name
console.log(MathUtils.PI); // 3.14159
console.log(MathUtils.circleArea(5)); // 78.53975
console.log(MathUtils.clamp(150, 0, 100)); // 100
(2) Blocos estáticos (TypeScript 5.0 / ES2022+)
class Config {
static host: string;
static port: number;
// Static Initialization Block
static {
Config.host = process.env.HOST ?? "localhost";
Config.port = Number(process.env.PORT) || 3000;
}
}
(3) A diferença entre membros estáticos e membros de instância
class Counter {
static totalCount: number = 0; // Shared by all instances
instanceCount: number = 0; // Each instance is independent
increment(): void {
Counter.totalCount++;
this.instanceCount++;
}
}
let c1 = new Counter();
let c2 = new Counter();
c1.increment();
c1.increment();
c2.increment();
console.log(`Examples1:${c1.instanceCount}`); // 2
console.log(`Examples2:${c2.instanceCount}`); // 1
console.log(`Total:${Counter.totalCount}`); // 3
▶ Exemplo: Classe com modificadores de acesso e construtor abreviado
Saída:
100C = 212F
0C = 32F
class Article {
constructor(
readonly id: number,
public title: string,
private _views: number = 0
) {}
get views(): number {
return this._views;
}
incrementViews(): void {
this._views++;
}
toString(): string {
return `[${this.id}] ${this.title} (${this.views} views)`;
}
}
let post = new Article(1, "Hello TypeScript");
post.incrementViews();
post.incrementViews();
console.log(post.toString()); // "[1] Hello TypeScript (2 views)"
// post._views; // ❌ private — cannot access from outside
Saída:
100C = 212F
0C = 32F
▶ Exemplo: Métodos de fábrica estáticos e propriedades readonly
Saída:
100C = 212F
0C = 32F
class Point {
constructor(
public readonly x: number,
public readonly y: number
) {}
static origin: Point = new Point(0, 0);
static fromAngle(angle: number, distance: number): Point {
return new Point(
Math.round(distance * Math.cos(angle)),
Math.round(distance * Math.sin(angle))
);
}
distanceTo(other: Point): number {
return Math.sqrt((this.x - other.x) ** 2 + (this.y - other.y) ** 2);
}
}
let p = Point.fromAngle(Math.PI / 4, 10);
console.log(`(${p.x}, ${p.y})`); // "(7, 7)"
console.log(p.distanceTo(Point.origin)); // "~10"
Saída:
100C = 212F
0C = 32F
❓ Perguntas Frequentes
P:
privateé realmente privado em tempo de execução? R: Não. Oprivatedo TypeScript é apenas uma verificação em tempo de compilação — as propriedades privadas ainda são acessíveis no código JavaScript compilado. A sintaxe#privateno ES2022 (campos privados) é o que proporciona verdadeira privacidade em tempo de execução. O TypeScript também suporta#private:class C { #secret = 1; }.
P: Quando se deve usar
privatee quando se deve usarprotected? R:privateé usado para detalhes internos de implementação que “somente a própria classe precisa”;protectedé usado para membros que “as subclasses também podem precisar acessar ou sobrescrever”. Se você estiver em dúvida, comece comprivate— você sempre pode alterá-lo paraprotectedmais tarde, se necessário (é mais seguro ser mais permissivo do que mais restritivo).
P: Qual é a diferença entre getters/setters e métodos comuns? R: Os métodos getter/setter fazem com que a leitura e a gravação de propriedades pareçam estar sendo acessadas diretamente (YIJIAN0PH), mas executam uma lógica personalizada nos bastidores. Os métodos comuns exigem chamadas explícitas (YIJIAN1PH). Recomenda-se usar getters/setters para propriedades expostas externamente (para realizar validação ou calcular propriedades) e métodos comuns para implementação interna.
P: É possível usar
thisem métodos estáticos? R: Em métodos estáticos, usa-sethisrefers to the classe itself (not an instância). Instatic create() { return new this(); },thisis equal to the current classe. However,thismay be lost in arrow functions or callbacks—it is recommended to use the classe name instead ofthis.
📖 Resumo
- No TypeScript, as classes exigem que as propriedades sejam declaradas antes de poderem ser utilizadas; as propriedades podem ser inicializadas na declaração, atribuídas no construtor ou
!verificadas. - Modificadores de acesso: public (padrão, acessível de fora da classe), protected (acessível às subclasses), private (acessível apenas dentro da classe)
- As propriedades de parâmetros simplificam a sintaxe para declarações de propriedades e atribuições no construtor
- Propriedades somente leitura só podem ser inicializadas na declaração ou no construtor
- Os métodos getter/setter executam uma lógica personalizada ao ler ou gravar uma propriedade; se houver um getter, mas não um setter, a propriedade é somente de leitura.
- Os membros estáticos pertencem à própria classe, e não às instâncias; são acessados por meio de
ClassName.member
📝 Exercícios
- Problema básico (Dificuldade ⭐): Crie uma classe
Rectangle(com propriedades de largura e altura) e implemente os métodosgetArea()egetPerimeter(). Simplifique o construtor utilizando propriedades parametrizadas. - Problema avançado (Dificuldade ⭐⭐): Crie uma classe
BankAccount— tornebalanceprivado, permita operações por meio dos métodosdepositewithdraw, exponha o saldo como somente leitura usando um getter e verifique se o saldo é suficiente antes de uma operaçãowithdraw. - Desafio (Dificuldade: ⭐⭐⭐): Implemente uma classe genérica
Stack<T>— armazene dados em um array privado, forneça os métodos push, pop, peek e size, implemente a propriedade size (somente leitura) usando getters e use um método estáticostatic fromArray<T>(items: T[]): Stack<T>para criar uma pilha a partir do array.