Classes
이 글은 노마드 코더의 타입스크립트 무료 강의를 보고 노트 정리를 한 글입니다.
강의링크
4.0 Classes
이번에는 객제지향 타입스크립트에 대해 배워보자.
타입스크립트로 클래스를 만드는 방법은 아래와 같다.
class Player {
constructor(
private firstName:string,
private lastName:string,
public nickName:string
)
}
타입스크립트에서는 constructor에서 public, private 속성을 부여할 수 있다.
const ttolbe= new Player("Ttolbe","Na","Tolby")
ttolbe.firstName;
ttolbe.nickName;
위와 같이 오브젝트를 만들고 firstName 속성을 불러오면 에러가 나지만 nickName은 에러가 나지 않는다. firstName은 private 속성을 지녔고 nickName은 public속성을 지녔기 때문이다.
타입스크립트가 가진 기능 중 하나는 abstract class 이다. 추상 클래스는 다른 클래스에게 상속할수 있다. 하지만 새로운 인스턴스를 만들 수는 없다.
abstract class User{
constructor(
private firstName:string,
private lastName:string,
public nickName:string
){}
}
class Player extends User{
}
const ttolbe= new User("Ttolbe","Na","Tolby")
위와 같이 User를 새로 만들려고 하면 오류가 발생한다.
추상 클래스 안에는 추상 메소드를 넣을 수 있다.
abstract class User{
constructor(
private firstName:string,
private lastName:string,
public nickName:string
){}
getFullName(){
return `${this.firstName} ${this.lastName}`
}
}
class Player extends User{
}
const ttolbe= new Player("Ttolbe","Na","Tolby")
ttolbe.getFullName()
추상 메소드로 클래스 안의 private 속성에 접근 가능하다. 한편 이 메소드를 아래와 같이 private 속성으로 변경하면 getFullName() 함수는 실행할수 없어 에러가 난다.
abstract class User{
constructor(
private firstName:string,
private lastName:string,
public nickName:string
){}
private getFullName(){
return `${this.firstName} ${this.lastName}`
}
}
또 다른 속성에는 protected가 있다. protected를 사용하면 public 속성 처럼 값에는 접근 가능하지만, 값을 변경 할 수는 없다.
abstract class User{
constructor(
protected firstName:string,
private lastName:string,
public nickName:string
){}
getFullName(){
return `${this.firstName} ${this.lastName}`
}
}
class Player extends User{
}
const ttolbe= new Player("Ttolbe","Na","Tolby")
ttolbe.nickName="nick"
ttolbe.firstName="Me"
위와 같이 코드를 짜면 nickName은 변경 가능하지만, firstName은 변경 되지 않아 에러가 발생한다.
4.1 Recap
지금 까지 배운 것을 응용해 해시맵을 만들어보자.
type Words={
[key:string]:string
}
//키와 값이 둘다 string인 object type
class Dict{
private words:Words,
constructor(){
this.words={}
}
add(word:Word){//클래스를 타입처럼 사용가능
if(this.words[word.term]===undefined){
this.words[word.term]=word.def
}
}
def(term:string){
return this.words[term]
}
}
class Word{
constructor(
public readonly term:string,//term은 수정 불가능하게
public def:string
){}
}
const kimchi = new Word("Kimchi","Korean Food")
const dict=new Dict()
dict.add(kimchi)
dict.def("kimchi")
4.2 Interfaces
인터페이스는 타입과 비슷하지만, 두가지 부분에서 다르다. 우선 지금 까지 타입을 선언하던 방법을 되돌아보자.
type Player={
nickName:string,
health:number
}
const Ttolbe:Player={
nickName:"TTolbe",
health:10
}
type Food=string
const kimchi:Food="kimchi"
또한 타입을 옵션으로 제한 할 수도 있다. 옵션 외의 값을 입력하면 틀렸다고 한다.
type Team="red"|"blue"|"yellow"
//Team의 옵션 제한
type Health=1|5|10
type Player={
nickName:string,
team:Team,
health:Health
}
const Ttolbe:Player={
nickName:"TTolbe",
team:"red",
health:10
}
인터페이스는 위와는 타입 선언 방식이 다르다.
type Team="red"|"blue"|"yellow"
type Health=1|5|10
interface Player {
nickName:string,
team:Team,
health:Health
}
const Ttolbe:Player={
nickName:"TTolbe",
team:"red",
health:10
}
인터페이스는 타입스크립트에게 오브젝트의 형태를 알리는 방식이다. 다만 타입은 인터페이스보다 활용도가 높다. 인터페이스는 오브젝트외에 다른 변수 모양은 특정 할 수 없다.
인터페이스는 아래와 같이 상속 또한 가능하다.
interface User{
name:string
}
interface Player extends User{
}
const ttolbe:Player={
name:"ttolbe"
}
위의 작업을 타입으로 적용해보자.
type User={
name:string
}
type Player=User&{
}
const ttolbe:Player={
name:"ttolbe"
}
인터페이스 역시 class처럼 readonly의 속성을 부여 가능하다.
type User={
readonly name:string
}
인터페이스의 또 다른 특징은 속성의 축적이다.
interface User{
name:string
}
interface User{
lastName:string
}
interface User{
health:number
}
const ttolbeUser:User={
name:"Ttolbe",
lastName:"Kim",
health:10
}
위와 같이 동일 인터페이스를 여러개 쓰면 타입스크립트가 알아서 합쳐준다. 하지만 타입은 속성의 축정이 불가능하다.
4.3 Interfaces part Two
다시 한번 추상 클래스에 대해 복습해보자.
abstract class User{
constructor(
protected firstName:string,
protected lastName:string,
){}
abstract sayHi(name:string):string;
abstract fullName():string
}
class Player extends User{
fullName(){
return `${this.firstName} ${this.lastName}`
}
sayHi(name:string){
return `Hello ${name}. My name is ${this.fullName()}`
}
}
추상 클래스는 상속 받는 클래스가 어떻게 행동해야하는지 알려주기 위해 존재한다.
다시 인터페이스로 돌아가자면, 우선 인터페이스는 자바스크립트로 컴파일 되지 않기 때문에 가볍다. 여기서 추상 클래스를 인터페이스로 변환해보자.
interface class User{
firstName:string,
lastName:string,
sayHi(name:string):string;
fullName():string
}
class Player implements User{
constructor(
private firstName:string,
private lastName:string
){}
fullName(){
return `${this.firstName} ${this.lastName}`
}
sayHi(name:string){
return `Hello ${name}. My name is ${this.fullName()}`
}
}
위의 코드를 적으면 에러가 난다. 인터페이스를 상속할 때는 property를 private 또는 protected 으로 설정할 수 없기 때문이다.
4.4 Recap
인터페이스는 원하는 메소드와 property를 클래스가 가지도록 강제 할 수 있다. 또한 인터페이스는 자바스크립트로 컴파일되지 않는다. 추상 클래스와 비슷한 보호를 제공하나, 자바스크립트에서는 보이지 않는 것이다.
또 다시 인터페이스와 타입의 차이를 복습해보자.
type PlayerA={
name:string
}
const playerA:PlayerA={
name:"ttolbe"
}
interface PlayerB {
name:string
}
const playerB:PlayerB={
name:"ttolbe"
}
위의 코드에서는 타입과 인터페이스 둘다 수행하는 역할이 같기 때문에 차이가 없어보인다. 하지만 타입스크립트에서 허용하는 둘의 기능은 좀 다르다.
일단 상속 방식의 차이를 보자.
type PlayerA={
name:string
}
type PlayerAA= PlayerA & {
lastName:string
}
//타입의 상속을
const playerA:PlayerAA={
name:"ttolbe",
lastName:"Kim"
}
interface PlayerB {
name:string
}
interface PlayerBB extends PlayerB{
lastName:string
}
const playerB:PlayerBB={
name:"ttolbe",
lastName:"kim"
}
둘이 비슷하지만 타입은 하나의 타입에 또다른 property를 추가할수 없다. 하지만 인터페이스는 가능하다.
interface PlayerB {
name:string
}
interface PlayerB{
lastName:string
}
const playerB:PlayerBB={
name:"ttolbe",
lastName:"kimm"
}
원한다면 인터페이스와 타입 모두 추상 클래스를 대신할수 있다.
type PlayerA={
firstName:string
}
class User implements PlayerA{
constructor(
public firstName:string
){}
}
interface PlayerB {
firstName:string
}
class User implements PlayerB{
constructor(
public firstName:string
){}
}
4.5 Polymorphism
전에 배웠듯이 다형성은 다른 모양의 코드를 가질 수 있게 해주는 것이며 다형성을 이루는 법은 제네릭을 사용하는 것이다.
브라우저에서 쓰는 로컬스토리지와 유사한 API를 만들어보자.
interface SStorage<T>{
[key:string]:T
}
class LocalStorage<T> {
private storage:SStorage<T>={}
set(key:string, value:T){
this.storage[key]=value
}
remove(key:string){
delete this.storage[key]
}
get(key:string):T{
return this.storage[key]
}
clear(){
this.storage={}
}
}
const stringsStorage= new LocalStorage<string>()
stringsStorage.set("key","hello")
stringsStorage.get("key")//result is string
const booleanStorage=new LocalStorage<boolean>()
booleanStorage.set("key",true)
booleanStorage.get("key")//result is boolean
'개발 > 타입스크립트' 카테고리의 다른 글
TypeScript로 블록체인 만들기(4) (0) | 2022.12.30 |
---|---|
TypeScript로 블록체인 만들기(2) (0) | 2022.12.28 |
TypeScript로 블록체인 만들기(1) (0) | 2022.12.27 |