class Player {
constructor(private firstName:string, public lastName: string) {
}
}
typescript는 매개변수만 작성해도 constructor 함수를 작성해줍니다.
class Player {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
TypeScript에서는 TypeScript에 미리 알리지 않고는 프로퍼티와 constructor을 초기화할 수 없습니다.
class Player {
// type annotation
first: string;
last: string;
score: number = 0;
constructor(first: string, last: string) {
this.first = first;
this.last = last;
}
}
const sungryul = new Player("zima", "blue");
클래스에서는 readonly를 사용할 수 있습니다.
class Player {
readonly first: string;
readonly last: string;
score: number = 0;
constructor(first: string, last: string) {
this.first = first;
this.last = last;
}
}
const han = new Player("zima", "blue");
// Cannot assign to 'first' because it is a read-only property
han.first = 'sungryul'
JavaScript와 TypeScript의 모든 클래스 프로퍼티와 메서드는 public으로 간주합니다.
따라서 public 접근 제어자는 필수는 아닙니다.
하지만 클래스 외부 또는 내부에서 누구든 프로퍼티나 메서드에 액세스 가능하다는 의미에서 public이라고 명시합니다.
class Player {
public readonly first: string;
public readonly last: string;
public score: number = 0;
constructor(first: string, last: string) {
this.first = first;
this.last = last;
}
}
const han = new Player("zima", "blue");
private 접근 제어자를 사용하면 해당 프로퍼티 또는 메서드가 오직 클래스의 내부에서만 접근 및 사용할 수 있다고 알려줄 수 있습니다.
class Player {
public readonly first: string;
public readonly last: string;
private score: number = 0;
constructor(first: string, last: string) {
this.first = first;
this.last = last;
}
}
const han = new Player("zima", "blue");
// Property 'score' is private and only accessible within class 'Player'
han.score
// score은 private이기 때문에 컴파일 되지 않음
Private class fields는 #를 변수명 앞에 붙여 사용하는 Javascript 코드입니다.
따라서 프로퍼티의 이름이 바뀌게 됩니다.
또한 Javascript 코드이기 때문에 컴파일 이후에도 프로퍼티를 보호합니다.
Private Access Modifier은 TypeScript에서 경고를 해주지만 경고를 무시하고 컴파일 하게 된다면 보호받을 수 없습니다.
class Player {
public readonly first: string;
public readonly last: string;
#score: number = 0;
constructor(first: string, last: string) {
this.first = first;
this.last = last;
}
}
const han = new Player("zima", "blue");
// Property '#score' is not accessible outside class 'Player' because it has a pribate identifier
han.#score
파라미터 프로퍼티 단축 구문을 사용하면 constructor에서 초기화하거나 별도의 파라미터를 설정할 필요가 없습니다.
class Player {
private score: number = 0;
constructor(public first: string, public last: string) {
// 따로 초기화 하지 않음
}
}
const han = new Player("zima", "blue");
TypeScript는 클래스에 getter와 setter 객체 접근자를 사용할 수 있습니다.
class Player {
constructor(
public first: string,
public last: string,
// getter, setter과 이름이 곂치기 때문에 변경
private _score: number
) {}
get fullName(): string {
return `${this.first} ${this.last}`;
}
// _score의 값을 반환
get score(): number {
return this._score;
}
// _score의 값을 변경
set score(newScore: number) {
if (newScore < 0) {
throw new Error("Score cannot be negative");
}
this._score = newScore;
}
}
const han = new Player("zima", "blue", 100);
elton.fullName;
elton.score = 99;
Protected는 상속 작업 때 사용됩니다.
private는 외부와 자식 클래스 모두 사용하지 못하지만,
Protected은 외부에서만 사용하지 못하고 자식클래스에서는 사용할 수 있습니다.
_score 프로퍼티는 private 이기 때문에 Player 클래스만 액세스할 수 있습니다.
따라서 해당 클래스를 상속하거나 확장한 자식 클래스에도 적용되지 않습니다.
class Player {
constructor(
public first: string,
public last: string,
private _score: number
) {}
get fullName(): string {
return `${this.first} ${this.last}`;
}
get score(): number {
return this._score;
}
set score(newScore: number) {
if (newScore < 0) {
throw new Error("Score cannot be negative");
}
this._score = newScore;
}
}
class SuperPlayer extends Player {
public isAdmin: boolean = true;
maxScore() {
// 오류
// Property '_score' is private and only accessible within class 'Player'
this._score = 999999;
}
}
하지만 이것을 protected로 변경하면 외부에서 _score에 액세스하는 게 불가능하지만, 자식 클래스는 제외됩니다.
class Player {
constructor(
public first: string,
public last: string,
// private에서 protected로 변경
protected _score: number
) {}
get fullName(): string {
return `${this.first} ${this.last}`;
}
get score(): number {
return this._score;
}
set score(newScore: number) {
if (newScore < 0) {
throw new Error("Score cannot be negative");
}
this._score = newScore;
}
}
class SuperPlayer extends Player {
public isAdmin: boolean = true;
maxScore() {
// _score 변경 가능
this._score = 999999;
}
}
implements 키워드는 class가 interface에 만족하는지 여부를 체크할 때 사용됩니다.
interface Colorful {
color: string;
}
// Bike 클래스는 implements Colorful 이기 때문에 color 프로퍼티를 가져야 합니다.
class Bike implements Colorful {
constructor(public color: string, public brand: string) {}
}
const bike1 = new Bike("red", "Harley");
한 개 이상의 interface를 사용할 수 있습니다.
interface Colorful {
color: string;
}
interface Printable {
print(): void;
}
class Jacket implements Colorful, Printable {
constructor(public brand: string, public color: string) {}
print() {
console.log(`${this.color} ${this.brand} Jacket`);
}
}
클래스로 type을 지정할 수 있습니다.
type Words = {
[key: string]: string;
};
class Word {
constructor(
public term: string,
public def: string
) {}
}
class Dict {
private words: Words
constructor() {
this.words = {}
}
// Word 클래스를 타입으로 사용하여 Word의 인스턴스를 매개변수로 받음
add(word: Word) {
if (this.words[word.term] === undefined) {
this.words[word.term] = word.def
}
}
def(term: string) {
return this.words[term]
}
}
const kimchi = new Word("kimchi", "한국의 음식");
const dict = new Dict();
// dict.add에는 Word 클래스의 인스턴스만 사용 가능
dict.add(kimchi)
console.log(dict.def("kimchi"))
// "한국의 음식"
Abstract 클래스는 TypeScript에만 있는 기능입니다.
abstract 키워드/제어자를 class 앞에 붙이면 다른 class가 상속 받을 수 있지만, 이 자체로는 더 이상 새 클래스를 만들 수 없다는 뜻이 됩니다.
abstract class Employee {
constructor(public first: string, public last: string) {}
}
// extends를 사용하여 Employee abstract을 하위 클래스에서 사용
class FullTimeEmployee extends Employee {
}
new FullTimeEmployee("zima", "blue")
abstract class Employee {
constructor(public first: string, public last: string) {}
};
// Cannot create an instance of an abstract class
new Employee();
abstract 클래스는 패턴을 정의하고 자식 클래스에서 시행돼야 하는 메서드를 정의하는 데 사용됩니다.
(Call Signatures만 작성)
또한 abstract 키워드를 사용해 하위 클래스에 반드시 존재해야 하는 메서드를 정의할 수 있습니다.
abstract class Employee {
// FullTimeEmployee의 super로 넘어온 인자를 받음
constructor(public first: string, public last: string) {}
// 하위 클래스에 반드시 시행되어야 하는 메서드
abstract getPay(): number;
greet() {
console.log("HELLO");
}
}
class FullTimeEmployee extends Employee {
constructor(first: string, last: string, private salary: number) {
super(first, last);
}
// Employee클래스를 상속 받았기 때문에 getPay 메서드를 하위 클래스에서 반드시 구현
getPay() {
return this.salary;
}
}
const person = new FullTimeEmployee("Sungryul", "Han", 40000);
console.log(person.getPay());
// 40000
Abstract 클래스를 사용하면 자바스크립트 코드로 컴파일 했을 때 Abstract 클래스가 사라지지 않고 남게 됩니다.
(자바스크립트에는 Abstract이라는 개념이 없기 때문에)
Interface를 사용하면 컴파일 했을 때 타입을 위해 사용한 Interface가 사라집니다.
(Interface를 사용하면 protected, private 프로퍼티 사용 불가)
abstract class User {
constructor(
protected firstName:string,
protected lastName:string
) {}
abstract fullName():string
abstract sayHi(name:string):string
}
class Player extends User {
fullName() {
return `${this.firstName} ${this.lastName}`
}
sayHi(name:string){
return `Hello ${name}. My name is ${this.fullName()}`
}
}
"use strict";
class User {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
class Player extends User {
fullName() {
return `${this.firstName} ${this.lastName}`;
}
sayHi(name) {
return `Hello ${name}. My name is ${this.fullName()}`;
}
}
interface User {
firstName:string,
lastName:string,
fullName():string,
sayHi(name:string):string
}
class Player implements User {
constructor(
public firstName:string,
public lastName:string,
) {}
fullName() {
return `${this.firstName} ${this.lastName}`
}
sayHi(name:string){
return `Hello ${name}. My name is ${this.fullName()}`
}
}
"use strict";
class Player {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
fullName() {
return `${this.firstName} ${this.lastName}`;
}
sayHi(name) {
return `Hello ${name}. My name is ${this.fullName()}`;
}
}