TypeScript는 객체지향 코드를 더 안전하고 좋게 만들도록 도와주는 기능을 제공한다.
보다시피 TS와 JS는 조금 다르다.
JS에서 class를 만들 때는 constructor()
함수를 사용하여 this.firstName = firstName;
이런식으로 보내줘야 한다.
class Player {
constructor(firstName, lastName, nickname){
this.firstName = firstName;
this.lastName = lastName;
this.nickname = nickname;
}
}
const rm = new Player("Kim", "Namjoon", "DuDu");
하지만 TS에서는 constructor()
로 파라미터
만 보내주면 된다.
필드가 어떤 보호 등급인지(접근 제어자: private, protected, public), 이름, 타입을 작성하면 된다.\
그러면 TS가 알아서 해준다.
class Player {
constructor(
//파라미터 보내기
//JS에서는 private, public 같은 기능 없지만 TS에서는 설정가능
private firstName: string,
private lastName: string,
public nickname: string,
) {}
}
const rm = new Player("Kim", "Namjoon", "DuDu");
rm.firstName; //❌ private이라서 이렇게는 접근 불가 => 오류 띄워줌
rm.lastName; //❌ private이라서 이렇게는 접근 불가 => 오류 띄워줌
rm.nickname; //✅ public이라서 접근 가능
TS와 객체지향 프로그램이 가지고 있는 좋은 것은 추상클래스(Abstract Class)
이다.
추상 클래스(Abstract Class)
는 오직 다른 클래스가 상속(inheritance) 받을 수만 있는 클래스이다.//추상클래스(Abstract Class)는 다른 클래스가 상속 받을 수 있는 클래스
abstract class User {
constructor(
private firstName: string,
private lastName: string,
public nickname: string,
) {}
}
//Player가 User를 상속한다고 알리기
class Player extends User {
}
const rm = new Player("Kim", "Namjoon", "DuDu")
rm.nickname; //✅ public이라서 접근 가능
new User
이렇게 사용할 수는 없다.abstract class User {
constructor(
private firstName: string,
private lastName: string,
public nickname: string,
) {}
//클래스 안에서 구현된 메서드(abstract method) 만들기
//firstName, lastName 합친 string 리턴해주는 메서드
getFullName(){
return `${this.firstName} ${this.lastName}`;
}
}
//클래스 생성
//Player 가 User를 상속한다고 알리기
class Player extends User {
}
//인스턴스 생성
const rm = new Player("Kim", "Namjoon", "DuDu")
rm.nickname; //✅ public이라서 접근 가능
rm.getFullName(); //✅ User에서 상속받았으니까 Player에서도 메서드 호출 가능
public
대신 private
을 사용하면 된다.private getFullName(){...}
그러면 이 메서드는 호출 할 수 없다.(참고)
메서드(method)는 클래스(class)안에 존재하는 함수이다.
getFullName(){
//이 부분이 메서드의 구현(implementation) 부분이다.
//👉 이런 구현 부분을 넣지 않으면 된다는 뜻임
return `${this.firstName} ${this.lastName}`;
//
}
추상 메서드
는 메서드를 구현(implementation)
하지 않은, 즉 코드가 없는 메서드이다.
추상 클래스 안에서 추상 메서드를 만들 수 있는데, 메서드를 구현
하는 대신 메서드의 call signature
만 적어 두면 된다.
abstract class User {
constructor(
private firstName: string,
private lastName: string,
private nickname: string,
//❗️ 닉네임을 private으로 바꿔보자
) {}
//말은 안되지만 getNickname 메서드를 만들어 보자.
//🔥 추상 메서드(abstract method)
//❗️ 메서드 안에 코드가 없음
//❗️ 즉, 구현하는 코드가 없고 콜 시그니처만 적어야 함
abstract getNickname():void
//📝 일반적인 메서드
//: 클래스 안에서 메서드 만들 때 메서드 안에 구현된 코드 있음
//firstName, lastName 합친 string 리턴해주는 메서드
getFullName(){
//메서드의 구현 부분
return `${this.firstName} ${this.lastName}`;
//
}
}
//클래스 생성
//Player 가 User를 상속한다고 알리기
class Player extends User {
}
//인스턴스 생성
const rm = new Player("Kim", "Namjoon", "DuDu") //🔥🔥🔥 여기서 오류뜸!
rm.nickname; //❌ private이라서 접근 불가
rm.getFullName(); //✅ User에서 상속받았으니까 Player에서 메서드 사용가능
추상 클래스가 아닌 Player가 User클래스로 부터 추상 멤버인 getNickname을 상속받았지만, 구현하지 않았다고 오류가 뜬다.
즉, Player가 getNickName을 구현해야 한다고 오류를 띄워 알려준다.
따라서 추상 메서드는 추상 클래스를 상속받는 모든 것들이 구현 해야 하는 메서드를 의미한다.
//🔥 User 추상 클래스의 nickname 프로퍼티가 private인 경우
class Player extends User {
//🔥 추상 메서드를 구현하려면 하위 클래스 안에서 구현해주면 된다.
getNickname(){
//그런데
//❌ User 추상 클래스의 nickname 프로퍼티가 private이기 때문에 이렇게 사용할 수가 없다.
console.log(this.nickname);
}
}
//인스턴스 생성
const rm = new Player("Kim", "Namjoon", "DuDu")
rm.nickname; //❌ User 인스턴스 바깥에서는 프로퍼티에 접근 불가
구분 | 선언한 클래스 안 (ex. 추상 클래스 안) | 상속받은 클래스 안 (자식 클래스 안) | 인스턴스 밖 |
---|---|---|---|
private | ✅ | ❌ | ❌ |
protected | ✅ | ✅ | ❌ |
public | ✅ | ✅ | ✅ |
private
으로 작성된 프로퍼티들은 인스턴스 밖에서 접근할 수 없고, 다른 자식 클래스에서도 접근할 수 없다.private
대신 protected
를 사용하면 된다.//추상클래스(Abstract Class)는 오직 다른 클래스가 상속 받을 수만 있는 클래스
//직접 새로운 인스턴스를 만들 수는 없다. 따라서 new User 이렇게 못 만듦
abstract class User {
constructor(
//✅ 필드 보호를 원하지만 하위클래스에서는 프로퍼티에 접근 가능하게 하려면
//private 대신 protected 적어주기
protected firstName: string,
protected lastName: string,
protected nickname: string,
) {}
//추상 메서드(abstract method) 만들기
//구현 하면 안되고 콜 시그니처만 적어야 함
abstract getNickname():void
//클래스 안에서 메서드 만들기
//firstName, lastName 합친 string 리턴해주는 메서드
getFullName(){
//메서드의 구현 부분
return `${this.firstName} ${this.lastName}`;
//
}
}
//클래스 생성
//Player 가 User를 상속한다고 알리기
class Player extends User {
//🔥 추상 메서드 구현하기
getNickname(){
//✅ User를 상속하는 Player 하위 클래스에서는 protected 프로퍼티에 접근 가능
console.log(this.nickname);
}
}
//인스턴스 생성
const rm = new Player("Kim", "Namjoon", "DuDu")
rm.nickname; //❌ User 인스턴스 바깥에서는 protected 프로퍼티에 접근 불가
rm.getFullName(); //✅ User에서 상속받았으니까 Player에서 추상 메서드 사용가능
해싱 알고리즘을 사용하는 해시맵으로 단어 사전 만들어 보기
//Words 타입은 오브젝트인데, string만을 프로퍼티로 가짐
type Words = {
[key:string]: string
//이 형식은 제한된 양의 프로퍼티 혹은 키를 가지는 타입을 정의하는 방법임
}
//예를 들면 이렇게
// let dict :Words = {
// "potato": "food",
// "strawberry": "food"
// }
//사전 클래스
class Dictionary {
//워드 오브젝트를 프라이빗으로 만들기
//그런데 컨스트럭터가 words를 지정하기를 원하지 않으므로
//컨스트럭터로부터 바로 초기화되지 않는 프로퍼티로 만들자
private words:Words
//그러고 나서 수동으로 초기화 하기
constructor(){
this.words = {}
}
//✅메서드 만들기
//사전에 새 단어를 추가하기 / 단어 찾기 / 단어 삭제 하기
//✅단어 추가하는 메서드
//🔥 Word 클래스를 타입처럼 사용할 수 있음
//word 파라미터가 Word 클래스의 인스턴스 이길 원한다면 이렇게 사용할 수 있다.
add(word:Word){
//주어진 단어가 아직 사전에 존재하지 않으면
if(this.words[word.term] === undefined){
//사전에 그 단어에 대한 정의에 추가하기
this.words[word.term] = word.definition;
}
}
//✅term 이용해 deffinition 찾는 메서드
deffintion(term:string){
return this.words[term]
}
//✅단어 삭제하는 메서드
remove(term: string){
//단어를 찾았을 때 단어가 있으면
if(this.words[term] !== undefined){
//그 단어 삭제
delete this.words[term]
}
}
//✅단어 업데이트하는 메서드
update(word: Word){
//단어 찾았을 때 그 단어가 있으면
if(this.words[word.term] !== undefined){
//단어 정의 업데이트하기 위해 새로 넣어주기
this.words[word.term] = word.definition;
}
}
}
//단어 클래
class Word {
constructor(
public term: string, //용어
public definition: string, //정의
){}
}
//단어 인스턴스 생성
const kimchi = new Word("kimchi", "a Korean dish of spicy pickled cabbage.")
const coffee = new Word("coffee", "커피가 커피지")
const greentea = new Word("greentea", "녹차 말차 루룰루루")
//사전 인스턴스 생성
const dict = new Dictionary();
//✅사전에 단어 추가하기
dict.add(kimchi);
dict.add(coffee);
dict.add(greentea);
//사전에 있는 단어
console.log(dict)
//✅단어의 정의 찾아보기
dict.deffintion("kimchi");
dict.deffintion("coffee");
dict.deffintion("greentea");
//업데이할 인스턴스 생성
const newCoffee = new Word("coffe", "콩 볶아 만든 카페인 차차차")
//✅커피 정의 업데이트하기
dict.update(newCoffee)
//✅사전에 단어 삭제하기
dict.remove("greentea")
아 근데 업데이트가 안되네 ;;;;