본문 바로가기

클래스 기본 문법

클래스의 속성과 생성자, 메서드, getter와 setter로 인스턴스를 만들고, 생성과 변경이 서로 다른 코드를 거친다는 점과 접근 제어자, 생성자 매개변수 속성, static 멤버가 어디에 속하는지 예제로 확인합니다.

같은 모양의 객체를 여러 개 만들고, 그 객체마다 같은 동작을 붙이고 싶을 때 클래스(class)를 씁니다. 자바스크립트는 원래 프로토타입(prototype)으로 객체가 동작을 나누어 쓰는 언어이고, ES2015부터는 이를 더 읽기 쉽게 적는 class 문법을 제공합니다. 타입스크립트는 이 문법 위에 속성과 매개변수의 타입, 멤버에 접근할 수 있는 범위를 더합니다.

이 글은 클래스를 선언하고 인스턴스를 만드는 기본 문법에서 시작해, 생성자와 setter가 서로 다른 시점에 실행된다는 점을 확인합니다. 이어서 멤버의 접근 범위를 짧게 소개하고, 인스턴스가 아니라 클래스 자체에 속하는 static 멤버를 봅니다. 예제는 ts-first 프로젝트에 classes.ts를 만들고 include를 그 파일로 바꾸어 확인합니다.

클래스 선언과 인스턴스 생성

클래스는 class 키워드와 이름으로 선언하며, 이름은 보통 첫 글자를 대문자로 쓰는 파스칼 케이스(PascalCase)로 짓습니다. 클래스 안에는 객체의 상태를 담는 속성(property)과, 객체를 처음 만들 때 실행되는 생성자(constructor), 객체의 동작인 메서드(method)를 적습니다.

class Person {
  name: string;
  age: number;
  private _job: string;

  constructor(name: string, age: number, job: string) {
    this.name = name;
    this.age = age;
    this._job = job;
  }

  greet(): string {
    return `안녕하세요, ${this.name}입니다. 저는 ${this.age}살이고 ${this._job}입니다.`;
  }

  get job(): string {
    return this._job;
  }

  set job(newJob: string) {
    if (newJob.length < 2) {
      console.log("직업명은 2글자 이상이어야 합니다.");
      return;
    }
    this._job = newJob;
  }
}

const person1 = new Person("김철수", 30, "개발자");
const person2 = new Person("이영희", 25, "디자이너");

console.log(person1.name, person1.age);
console.log(person1.greet());
console.log(person2.job);

person2.job = "마케터";
console.log(person2.greet());
person2.job = "SE";
console.log(person2.job);
김철수 30
안녕하세요, 김철수입니다. 저는 30살이고 개발자입니다.
디자이너
안녕하세요, 이영희입니다. 저는 25살이고 마케터입니다.
SE

new Person(...)은 새 객체를 만들고 생성자를 실행해, 넘긴 값을 그 객체의 속성에 저장한 뒤 돌려줍니다. 생성자와 메서드 안의 this는 지금 만들고 있는 객체나, 메서드를 부를 때 거친 객체를 가리키므로, person1과 person2는 같은 클래스로 만들었어도 각자의 상태를 따로 가집니다. 아래 그림은 이 생성 과정과 두 인스턴스의 상태를 단계별로 보여 줍니다.

클래스 인스턴스 생성 생명주기 — 상태 추적

new Person에서 this 초기화 뒤 독립 person1/person2의 값과 후속 setter/greet 결과가 바뀐다. 생성자와 setter 검증이 공유되지 않는 점을 같은 객체 정체성으로 표현할 수 있다.

new Person 호출은 생성자로 초기화한 인스턴스를 반환합니다. person1과 person2의 상태는 독립이고 getter와 setter는 구현된 코드를 실행합니다.

TYPE / RUNTIME / CONTRACT

new가 생성자를 실행해 각 인스턴스 상태를 만듭니다

Person의 생성자는 전달된 name·age·job을 각 객체에 저장합니다. 초기화했다고 해서 입력 값의 유효성을 자동 검사하는 것은 아닙니다.

호출에서 생성된 인스턴스로newPerson호출→constructor직접초기화→별도인스턴스의3노드2간선이다. getter와setter는생성의필수단계가아니며후속접근시실행된다. 생성자의검사와setter검사는자동공유되지않는다.
new Personname · age · job
연결 관계new Person · name · age · job → constructor · this의 상태 초기화
constructorthis의 상태 초기화
연결 관계constructor · this의 상태 초기화 → 새 인스턴스 · 후속 메서드 · 접근자
새 인스턴스후속 메서드 · 접근자
호출에서 생성된 인스턴스로 · 모바일newPerson호출→constructor직접초기화→별도인스턴스의3노드2간선이다. getter와setter는생성의필수단계가아니며후속접근시실행된다. 생성자의검사와setter검사는자동공유되지않는다. 모바일에서도 노드와 연결 방향·독립 경로가 같다.
new Personname · age · job
연결 관계new Person · name · age · job → constructor · this의 상태 초기화
constructorthis의 상태 초기화
연결 관계constructor · this의 상태 초기화 → 새 인스턴스 · 후속 메서드 · 접근자
새 인스턴스후속 메서드 · 접근자

TWO INSTANCES

서로 다른 name·age·job

김철수·30·개발자와 이영희·25·디자이너를 저장한 객체 두 개가 생성됩니다. person2.job 변경은 person1의 상태를 바꾸지 않습니다.

ACCESSORS

속성 접근으로 코드 실행

person2.job = "마케터"는 setter를 실행합니다. 길이 2인 SE는 newJob.length < 2 조건에 걸리지 않아 변경됩니다.

PARAMETER PROPERTY

선언과 할당을 줄이는 별도 문법

CompactPerson 생성자의 public·private 매개변수는 속성을 동시에 선언하고 초기화합니다. 모든 클래스 생성에 이 문법이 필수인 것은 아닙니다.

VALIDATION

검증은 작성한 로직에 따릅니다

Person 생성자에는 age·job 유효성 검사가 없습니다. setter는 길이만 확인하고 실패 시 로그 후 변경을 건너뜁니다. 타입 표기가 런타임 검증을 추가하지 않습니다.

필드·생성자·메서드는 역할이 다릅니다. getter·setter와 매개변수 속성을 생성의 필수 연속 단계로 보지 않습니다.

이 예의 조건

  • 원도표의 전체 구조와 설명은 위 관계도와 표에서 유지합니다. 아래 인쇄 표에도 원도표의 관계·조건·라벨·설명·주석을 보존합니다.
  • 두 관찰 칸의 위치는 고정입니다. 관찰 상태는 해당 순간의 값이며, 동작·이유는 그 조건에서의 판정과 변화 원인입니다. 독립 비교와 실패 분기는 별도 조건으로 읽고 모든 분기를 한 요청의 필수 실행 순서로 이어 읽지 않습니다.
관계도의 보충 설명
원도표의 전체 관계·조건·설명
구분내용
전체 관계·조건 설명new Person 호출→constructor 직접 초기화→별도 인스턴스의 노드 3개·간선 2개다. getter와 setter는 생성의 필수 단계가 아니며 후속 접근 시 실행된다. 생성자의 검사와 setter 검사는 자동으로 공유되지 않는다.
전체 관계·조건 설명new Person 호출→constructor 직접 초기화→별도 인스턴스의 노드 3개·간선 2개다. getter와 setter는 생성의 필수 단계가 아니며 후속 접근 시 실행된다. 생성자의 검사와 setter 검사는 자동으로 공유되지 않는다. 모바일에서도 노드와 연결 방향·독립 경로가 같다.
원도표 설명person2.job = "마케터"는 setter를 실행합니다. 길이 2인 SE는 newJob.length < 2 조건에 걸리지 않아 변경됩니다.
전체 상태와 변화 근거
장면현재 관찰값설명변화 이유
new Personperson: 새 인스턴스 / 초기화: name·age·job호출값으로 constructor가 해당 this를 초기화한다getter와 setter는 생성에 반드시 필요한 단계가 아니다
독립된 두 객체person1: 김철수 유지 / person2: 독립 nameperson1과 person2는 서로 다른 상태를 읽는다같은 클래스 정의가 같은 인스턴스 상태를 뜻하지 않는다
person2 변경person1: 김철수 / person2: 지수·25·SEperson2의 name을 지수로 바꾸면 그 객체의 greet만 바뀐다setter 조건과 constructor 조건은 자동으로 공유되지 않는다

클래스 인스턴스 생성 생명주기 — 상태 추적

new Person에서 this 초기화 뒤 독립 person1/person2의 값과 후속 setter/greet 결과가 바뀐다. 생성자와 setter 검증이 공유되지 않는 점을 같은 객체 정체성으로 표현할 수 있다.

new Person 호출은 생성자로 초기화한 인스턴스를 반환합니다. person1과 person2의 상태는 독립이고 getter와 setter는 구현된 코드를 실행합니다.

TYPE / RUNTIME / CONTRACT

new가 생성자를 실행해 각 인스턴스 상태를 만듭니다

Person의 생성자는 전달된 name·age·job을 각 객체에 저장합니다. 초기화했다고 해서 입력 값의 유효성을 자동 검사하는 것은 아닙니다.

호출에서 생성된 인스턴스로newPerson호출→constructor직접초기화→별도인스턴스의3노드2간선이다. getter와setter는생성의필수단계가아니며후속접근시실행된다. 생성자의검사와setter검사는자동공유되지않는다.
new Personname · age · job
연결 관계new Person · name · age · job → constructor · this의 상태 초기화
constructorthis의 상태 초기화
연결 관계constructor · this의 상태 초기화 → 새 인스턴스 · 후속 메서드 · 접근자
새 인스턴스후속 메서드 · 접근자
호출에서 생성된 인스턴스로 · 모바일newPerson호출→constructor직접초기화→별도인스턴스의3노드2간선이다. getter와setter는생성의필수단계가아니며후속접근시실행된다. 생성자의검사와setter검사는자동공유되지않는다. 모바일에서도 노드와 연결 방향·독립 경로가 같다.
new Personname · age · job
연결 관계new Person · name · age · job → constructor · this의 상태 초기화
constructorthis의 상태 초기화
연결 관계constructor · this의 상태 초기화 → 새 인스턴스 · 후속 메서드 · 접근자
새 인스턴스후속 메서드 · 접근자

TWO INSTANCES

서로 다른 name·age·job

김철수·30·개발자와 이영희·25·디자이너를 저장한 객체 두 개가 생성됩니다. person2.job 변경은 person1의 상태를 바꾸지 않습니다.

ACCESSORS

속성 접근으로 코드 실행

person2.job = "마케터"는 setter를 실행합니다. 길이 2인 SE는 newJob.length < 2 조건에 걸리지 않아 변경됩니다.

PARAMETER PROPERTY

선언과 할당을 줄이는 별도 문법

CompactPerson 생성자의 public·private 매개변수는 속성을 동시에 선언하고 초기화합니다. 모든 클래스 생성에 이 문법이 필수인 것은 아닙니다.

VALIDATION

검증은 작성한 로직에 따릅니다

Person 생성자에는 age·job 유효성 검사가 없습니다. setter는 길이만 확인하고 실패 시 로그 후 변경을 건너뜁니다. 타입 표기가 런타임 검증을 추가하지 않습니다.

필드·생성자·메서드는 역할이 다릅니다. getter·setter와 매개변수 속성을 생성의 필수 연속 단계로 보지 않습니다.

이 예의 조건

  • 원도표의 전체 구조와 설명은 위 관계도와 표에서 유지합니다. 아래 인쇄 표에도 원도표의 관계·조건·라벨·설명·주석을 보존합니다.
  • 두 관찰 칸의 위치는 고정입니다. 관찰 상태는 해당 순간의 값이며, 동작·이유는 그 조건에서의 판정과 변화 원인입니다. 독립 비교와 실패 분기는 별도 조건으로 읽고 모든 분기를 한 요청의 필수 실행 순서로 이어 읽지 않습니다.

관계도의 보충 설명

원도표의 전체 관계·조건·설명
구분내용
전체 관계·조건 설명new Person 호출→constructor 직접 초기화→별도 인스턴스의 노드 3개·간선 2개다. getter와 setter는 생성의 필수 단계가 아니며 후속 접근 시 실행된다. 생성자의 검사와 setter 검사는 자동으로 공유되지 않는다.
전체 관계·조건 설명new Person 호출→constructor 직접 초기화→별도 인스턴스의 노드 3개·간선 2개다. getter와 setter는 생성의 필수 단계가 아니며 후속 접근 시 실행된다. 생성자의 검사와 setter 검사는 자동으로 공유되지 않는다. 모바일에서도 노드와 연결 방향·독립 경로가 같다.
원도표 설명person2.job = "마케터"는 setter를 실행합니다. 길이 2인 SE는 newJob.length < 2 조건에 걸리지 않아 변경됩니다.
전체 상태와 변화 근거
장면현재 관찰값설명변화 이유
new Personperson: 새 인스턴스 / 초기화: name·age·job호출값으로 constructor가 해당 this를 초기화한다getter와 setter는 생성에 반드시 필요한 단계가 아니다
독립된 두 객체person1: 김철수 유지 / person2: 독립 nameperson1과 person2는 서로 다른 상태를 읽는다같은 클래스 정의가 같은 인스턴스 상태를 뜻하지 않는다
person2 변경person1: 김철수 / person2: 지수·25·SEperson2의 name을 지수로 바꾸면 그 객체의 greet만 바뀐다setter 조건과 constructor 조건은 자동으로 공유되지 않는다

get job()과 set job()은 접근자(accessor)라고 부르는, 속성처럼 읽고 쓰지만 실제로는 함수가 실행되는 멤버입니다. person2.job을 읽으면 getter가 _job을 돌려주고, person2.job = "마케터"처럼 값을 넣으면 setter가 길이를 검사한 뒤 _job을 바꿉니다. "SE"는 두 글자여서 검사를 통과하므로 그대로 저장됩니다.

속성을 선언만 하고 값을 넣지 않으면, strict에 포함된 strictPropertyInitialization이 이를 알려 줍니다. 예를 들어 생성자에서 this.age = age;를 빠뜨리면 Property 'age' has no initializer and is not definitely assigned in the constructor.라는 TS2564가 나옵니다. 속성은 선언할 때 초기값을 주거나 생성자에서 반드시 값을 넣어야 합니다.

생성과 변경은 다른 코드를 거친다

setter의 길이 검사는 값을 넣을 때만 실행됩니다. 생성자는 _job에 바로 저장하므로, 같은 값이라도 어느 경로로 들어오느냐에 따라 결과가 달라집니다. 앞의 코드에 이어서 다음을 실행해 봅니다.

person1.job = "한";
console.log(person1.job);

const shortJobPerson = new Person("민지", 20, "한");
console.log(shortJobPerson.job);
직업명은 2글자 이상이어야 합니다.
개발자
한

첫 대입은 setter가 안내 문구를 출력하고 return하므로 person1의 직업은 개발자로 남습니다. 하지만 생성자에는 같은 검사가 없어서, new Person("민지", 20, "한")은 한 글자 직업을 그대로 저장합니다. 지켜야 할 조건이 있다면 생성자와 setter가 같은 검증 함수를 함께 쓰도록 만들어야 하며, 이 예제의 Person은 아직 그렇게 완성된 모델이 아닙니다.

더 깊이: 클래스 필드는 대입이 아니라 정의다

setter를 거치지 않는 길은 생성자만이 아닙니다. 타입스크립트는 클래스 필드(class field)가 자바스크립트 표준이 되기 훨씬 전에 이 문법을 먼저 구현했고, 처음에는 foo = 100 같은 필드 선언을 생성자 안의 this.foo = 100 대입으로 바꾸어 출력했습니다. 그런데 표준으로 정해진 클래스 필드는 대입이 아니라 Object.defineProperty처럼 객체에 속성을 직접 정의하는 방식으로 동작합니다. TypeScript 3.7은 이 표준 동작으로 바꾸는 useDefineForClassFields 옵션을 들였고, Handbook은 target이 ES2022 이상이거나 이 옵션이 켜져 있으면 표준 동작을 따른다고 설명합니다. 이 교재의 target인 es2022가 여기에 해당합니다.

TypeScript 3.7 릴리스 노트는 두 동작의 차이를 두 가지로 정리합니다. 첫째, 필드는 정의로 만들어지므로 부모 클래스에 같은 이름의 setter가 있어도 그 setter가 불리지 않고 덮어써집니다. 둘째, 초기값이 없는 필드 선언도 언제나 undefined로 정의됩니다. 그래서 자식 클래스가 부모에게서 받은 속성의 타입만 좁히려고 resident: Dog;처럼 다시 선언하면, 부모 생성자가 넣어 둔 값이 super() 뒤에 undefined로 덮입니다. 출력에 아무 코드도 남기지 않고 타입만 다시 적으려면 declare resident: Dog;처럼 declare를 붙입니다.

멤버의 접근 범위

타입스크립트는 멤버마다 접근할 수 있는 범위를 접근 제어자(access modifier)로 정합니다. 아무것도 적지 않은 멤버는 어디서나 쓸 수 있는 public이고, private는 그 클래스 안에서만, protected는 그 클래스와, 그 클래스를 상속한 자식 클래스(subclass) 안에서만 쓸 수 있습니다.

class PrivateExample {
  private secretCode: string;

  constructor(code: string) {
    this.secretCode = code;
  }

  revealCode(): string {
    return `비밀 코드: ${this.secretCode}`;
  }
}

const pve = new PrivateExample("MY_CODE");
console.log(pve.revealCode());
비밀 코드: MY_CODE

클래스 밖에서 pve.secretCode를 읽으면 Property 'secretCode' is private and only accessible within class 'PrivateExample'.이라는 TS2341이 나옵니다. 다만 타입스크립트의 private는 검사에서만 접근을 막고 컴파일한 자바스크립트에서는 지워지므로, 실행 중에는 일반 속성과 같습니다. 실행 중에도 감추려면 이름 앞에 #를 붙이는 자바스크립트의 비공개 필드(private field)를 쓰며, 두 방식의 차이와 protected는 다음 글에서 자세히 봅니다.

생성자의 매개변수 앞에 접근 제어자나 readonly를 붙이면, 같은 이름의 속성을 선언하고 값을 넣는 일을 한 번에 할 수 있습니다. 이것을 매개변수 속성(parameter property)이라고 합니다.

class CompactPerson {
  constructor(public name: string, public age: number, private secretInfo: string) {}

  hint(): string {
    return `${this.secretInfo.length}글자의 비밀`;
  }
}

const compactP = new CompactPerson("김효진", 28, "비밀 일기");
console.log(compactP.name, compactP.age, compactP.hint());
김효진 28 5글자의 비밀

public name: string은 name 속성을 선언하고, 생성자가 시작할 때 this.name = name;을 실행하는 코드로 바뀝니다. 이름만 적은 매개변수는 생성자 안에서만 쓰는 지역 변수이고, 제어자를 붙여야 객체의 속성으로 남습니다. 이 문법은 새 자바스크립트 코드를 만들어 내므로, 1장에서 본 Node.js의 타입 제거 실행이나 erasableSyntaxOnly와는 함께 쓸 수 없습니다.

static 멤버

static을 붙인 멤버는 각 인스턴스가 아니라 클래스 자체에 속합니다. 그래서 new로 인스턴스를 만들지 않고 MathUtil.PI처럼 클래스 이름으로 바로 쓰며, 모든 인스턴스가 함께 쓰는 값이나 인스턴스의 상태가 필요 없는 도구 함수를 둘 때 씁니다.

class MathUtil {
  static PI: number = 3.14159;

  static calculateCircleArea(radius: number): number {
    return this.PI * radius * radius;
  }

  getInstancePi(): number {
    return MathUtil.PI;
  }
}

console.log(MathUtil.PI);
console.log(MathUtil.calculateCircleArea(5));

const util = new MathUtil();
console.log(util.getInstancePi());
3.14159
78.53975
3.14159

MathUtil.calculateCircleArea(5)는 클래스를 통해 부른 정적 메서드이므로, 그 안의 this는 클래스 자체를 가리키고 this.PI가 3.14159를 읽습니다. 인스턴스 메서드인 getInstancePi에서는 this가 인스턴스이므로 클래스 이름으로 MathUtil.PI를 읽었습니다. 정적 메서드를 인스턴스로 부른 util.calculateCircleArea(10)은 Property 'calculateCircleArea' does not exist on type 'MathUtil'. Did you mean to access the static member 'MathUtil.calculateCircleArea' instead?라는 TS2576으로 진단됩니다.

MathUtil.PI와 calculateCircleArea는 static 멤버이며 클래스 객체로 접근합니다. 인스턴스 상태와 접근 제한, JavaScript #private의 런타임 은닉을 별도로 비교합니다.

TYPE / RUNTIME / CONTRACT

멤버의 소속과 접근 범위는 서로 다른 기준입니다

인스턴스 상태는 객체에, static은 클래스 객체에 속합니다. public·protected·private는 TypeScript에서 멤버 접근을 검사합니다.

INSTANCE

객체의 상태와 메서드

Person의 name·age·job은 객체별 상태입니다. person1.greet()처럼 객체가 receiver인 호출은 그 객체의 this를 사용합니다.

STATIC

클래스 객체의 멤버

MathUtil.PI는 3.14159, 반지름 5의 면적은 78.53975입니다. util.calculateCircleArea는 인스턴스 멤버가 아니므로 오류입니다.

ACCESS

정적 접근 제한

public은 외부에서 접근할 수 있고 protected는 클래스와 파생 클래스의 허용 문맥, private는 선언 클래스의 허용 문맥에서 접근합니다. 이 선택은 instance/static 소속과 독립입니다.

#PRIVATE

JavaScript가 은닉을 강제

TypeScript private 접근 제한은 출력에서 제거되지만 JavaScript #field는 런타임에서도 강제됩니다. 본문 코드는 TypeScript private를 사용하며 #field는 비교 설명입니다.

상태 없는 기능은 모듈 함수로 표현할 수도 있습니다. 공유하는 mutable static 상태는 별도의 수명과 테스트 관리가 필요합니다.

위 그림처럼 멤버가 어디에 속하는지와 어디서 접근할 수 있는지는 서로 다른 기준입니다. 인스턴스의 상태는 각 객체에, static 멤버는 클래스 객체에 속하고, public과 protected, private는 그와 별개로 접근할 수 있는 코드의 범위를 정합니다. 멤버를 설계할 때는 객체마다 다른 상태인지, 바깥에 공개할 기능인지, 클래스 전체가 함께 쓰는 도구인지를 먼저 나누면 제어자와 static을 고르기 쉽습니다.

정리

  • 클래스는 속성과 생성자, 메서드를 묶어 같은 모양의 객체를 만들며, new가 생성자를 실행해 각 인스턴스의 상태를 따로 만듭니다.
  • strictPropertyInitialization은 초기값도 없고 생성자에서 값을 넣지도 않은 속성을 TS2564로 알려 줍니다.
  • getter와 setter는 속성처럼 쓰는 함수이며, setter의 검사는 생성자를 거치는 값에는 적용되지 않습니다.
  • private와 protected는 검사에서만 접근을 막고, 실행 중에도 감추려면 # 비공개 필드를 씁니다.
  • 매개변수 속성은 속성의 선언과 대입을 한 번에 하지만, 새 코드를 만드는 문법이어서 타입 제거 실행과는 함께 쓸 수 없습니다.
  • static 멤버는 클래스 자체에 속해 클래스 이름으로 쓰며, 인스턴스로 부르면 TS2576이 나옵니다.

연습 문제

1. 인스턴스와 클래스의 상태

이 글의 코드를 모두 실행한 상태에서 person2.name = "지수";로 바꾸면, person1.name과 person2.greet()는 무엇을 돌려주나요? MathUtil.PI = 3;을 넣은 뒤 util.getInstancePi()는 무엇을 돌려주고, util.PI는 읽을 수 있나요?

해설 보기

person1.name은 그대로 김철수이고, person2는 자기 이름만 바뀌며 마지막 직업이 SE이므로 안녕하세요, 지수입니다. 저는 25살이고 SE입니다.를 돌려줍니다. PI는 readonly가 아닌 정적 속성이므로 3이 저장되고, util.getInstancePi()도 클래스 객체의 지금 값 3을 읽습니다. util.PI는 인스턴스의 멤버가 아니어서 MathUtil.PI로 쓰라는 TS2576이 나옵니다.

2. 초기화하지 않은 속성

class Box { width: number; height = 10; }을 선언하면 어떤 진단이 나오나요? 이 진단을 없애는 방법을 두 가지 적어 보세요.

해설 보기

height는 초기값이 있지만 width는 어디서도 값을 넣지 않으므로 Property 'width' has no initializer and is not definitely assigned in the constructor.가 나옵니다. width = 0;처럼 초기값을 주거나, constructor(width: number) { this.width = width; }처럼 생성자에서 값을 넣으면 진단이 사라집니다. 값을 다른 곳에서 반드시 넣는다고 확신할 때만 width!: number;처럼 확정 할당 단언을 쓰며, 이 단언은 실제로 값을 넣어 주지 않습니다.

3. 매개변수 속성과 지역 매개변수

class Item { constructor(public title: string, price: number) {} }로 만든 new Item("펜", 1000)에서 item.title과 item.price는 각각 읽을 수 있나요?

해설 보기

title에는 public이 붙어 있으므로 속성으로 저장되어 item.title은 "펜"을 돌려줍니다. price는 제어자가 없는 평범한 매개변수여서 생성자 안에서만 쓰이고 객체의 속성이 되지 않으므로, item.price는 Property 'price' does not exist on type 'Item'.으로 진단됩니다. 매개변수 속성은 제어자나 readonly를 붙였을 때만 만들어집니다.

다음 글 접근 제어자에서는 public과 private, protected가 각각 어디서 접근을 허용하는지와, 타입스크립트의 private와 자바스크립트의 # 비공개 필드가 어떻게 다른지 자세히 비교합니다.