
typescript는 객체지향코드(javascript)를 더 안전하고 좋게 만들도록 도와주는 기능을 제공한다
Typescript는 필드가 어떠한 보호등급인지(접근제어자), 이름, 타입을 써주기만 하면 된다
// Typescript 방식
class User{
constructor(
private firstName: string,
private LastName: string
) {}
}
// 아래 위 같은 의미의 코드다
//Javascript 방식
class User{
constructor(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
}
}
// Typescript 방식
class User{
constructor(
private firstName: string,
private LastName: string,
public nickname: string
) {}
}
const hong = new User("hong", "yunsu", "angela")
// hong.firstName 이건 오류가 난다 firstName은 private이다
// private란? 클래스 기반 객체 지향 언어가 지원하는 접근 제한자
hong.nickname // 정상작동 public이라서
//Javascript 방식
class User{
constructor(firstName, lastName){
this.firstName = firstName;
this.lastName = lastName;
this.nickname = nickname;
}
}
const hong = new User("hong", "yunsu", "angela")
hong.firstName; // 이건 정상작동
추상클래스란?
다른 클래스가 상속 받을 수 있는 클래스
추상클래스는 인스턴스를 만들 수 없다
추상클래스는 오직 다른 곳에서 상속을 받을수만 있는 클래스
"넌 추상클래스를 상속받을 수만 있고, 직접적으로 인스턴스를 만들지는 못해"
abstract class User(
constructor(
private firstName: string,
private LastName: string,
public nickname: string
) {}
}
class Hong extends User{
}
const hong = new Hong("hong", "yunsu", "angela");
abstract class User(
constructor(
private firstName: string,
private LastName: string,
public nickname: string
) {}
getFullName(){
return `${this.firstName} ${this.lastName}`
}
}
class Hong extends User{
}
const hong = new Hong("hong", "yunsu", "angela");
hong.getFullName(); // Hong은 User를 상속받았으니까 사용가능하다
// 단, getFullName() 앞에 private가 붙으면 hong.getFullName() 이 코드는 오류가 난다
// 여기서 알 수 있는건, private, public이 property뿐만아니라 method에서도 작동한다
// 하지만 js에서는 오류가 나지 않고 작동한다
// 위 코드의 getFullName
getFullName(){
return `${this.firstName} ${this.lastName}`
// 이 return부분이 없으면 안된다
// 이 부분이 메소드의 implementation(구현)이다
}
추상클래스 안에서는 추상메소드를 만들 수 있다
하지만 메소드를 구현하면 안되고, call signature만 적어둬야한다
abstract class User(
constructor(
private firstName: string,
private LastName: string,
private nickname: string
) {}
// User 추상클래스가 getNickName이라는 추상메소드를 가지고 리턴값은 void
abstract getNickName(): void;
getFullName(){
return `${this.firstName} ${this.lastName}`
}
}
class Hong extends User{
// getNickName을 구현해야한다
getNickName(){
// console.log(this.nickname)을 사용하지 못한다. 왜? private property로 만들었기 때문에
}
}
const hong = new Hong("hong", "yunsu", "angela");
hong.getFullName();
property를 private로 만든다면, 그 클래스를 상속하였을지라도 그 property에 접근할 수 없다
왜? 이건 필드를 보호하기 위한 방법이 2개만 있는게 아니라서 그렇다. protected도 있다.
protected란?
필드가 외부로부터는 보호되지만 다른 자식 클래스에서는 사용하기를 원한다면 사용한다
private의 property들은 당연히 인스턴스 밖에서 접근할 수가 없고 다른 자식 클래스에도 접근할 수가 없다
abstract클래스는 추상클래스여서 인스턴스화 할 수 없다
abstract class User(
constructor(
protected firstName: string,
protected LastName: string,
protected nickname: string
) {}
// User 추상클래스가 getNickName이라는 추상메소드를 가지고 리턴값은 void
abstract getNickName(): void;
getFullName(){
return `${this.firstName} ${this.lastName}`
}
}
class Hong extends User{
// getNickName을 구현해야한다
getNickName(){
this.getFullName(); // 가능하다 클래스 내에서는 가능하다
console.log(this.nickname); // 가능하다
}
}
const hong = new Hong("hong", "yunsu", "angela");
hong.getFullName();
// hong.firstName 이건 안된다. 왜? protected라서
// 즉, 클래스 밖에서는 접근할 수 없다는 의미
정리
- 추상 클래스(User)는 직접적으로 인스턴스를 만들지 못하는 클래스다
그러나 그 클래스를 상속할 수는 있다
추상 클래스(User)에서 getFullName의 예시처럼 메소드를 구현한다면
상속받는 클래스(Hong)는 getFullName을 호출할 수 있게 된다
또, 메소드를 보호할 수도 있다.// 기본적으로는 public이지만 private, protected도 가능하다 private getFullName(){ return `${this.firstName} ${this.lastName}` }
- 추상 메소드는 구현이 되어있지 않은(코드가 없는) 메소드다
call signature만 가지고 있는데, 함수의 이름과 argument를 안받을때도 있지만
argument를 받을 경우 argument의 이름과 타입 그리고 함수의 리턴타입을 정의할 수 있다
예) abstract getNickName(): void;
추상메소드가 있는 경우, 추상 클래스를 상속받는 클래스에서 추상메소드를 구현해주어야 한다
예) getNickName() 위의 예제- public, private, protected의 차이
기본적으로 모든 것은 public이다
constructor의 내부를 private로 바꾸면 User 클래스는 Hong클래스에서 상속을 못한다
private는 User클래스 내에서만 접근이 가능하다
User클래스를 상속하는 모든 클래스에서만 사용가능하도록 만들고 싶을 경우에는 protected를 사용하면 된다
(public은 외부의 모든 곳에서 사용가능하게 만드는 것)
해시맵 만들기(단어 사전)
type Words = {
[key:string]: string
// Words 타입이 string만을 property로 가지는 object라는 의미
}
class Dictionary{
private words: Words
constructor(){
this.words = {} // 수동으로 초기화시킴
}
add(word: Word){ // 클래스를 타입처럼 사용할 수 있다
// word 파라미터가 Word클래스의 인스턴스이기를 원하면 이렇게 쓸 수 있다
if(this.words[word.term] === undefined){
this.words[word.term] = word.def;
}
}
// term을 사용해 word를 찾는 메소드
def(term: string){
return this.words[term]
}
}
class Word {
constructor(
public term: string,
public def : string
){}
}
const kimchi = new Word("kimchi", "한국의 음식")
const dict = new Dictionary()
dict.add(kimchi);
dict.def("kimchi")