- Interface
- Polymorphism
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()}`;
}
}
🔻 JS 코드
"use strict";
// 🔻 User은 new 키워드로 인스턴스를 생성할 수 없으므로 아래 constructor 코드는 불필요하다.
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()}`;
}
}
위와 같이 User은 그저 청사진 역할이라 객체를 생성하지 못한다.
-> 그럼에도 constructor 메서드가 존재하는데, 이는 불필요한 코드라고 볼 수 있다.
이럴 때 우리는 추상화를 interface
로 진행한다!
✅ interface는 컴파일시 JS로 바뀌지 않고 사라지기 때문에 가볍다.
interface User {
firstName: string,
lastName: string,
sayHi(name:string):string
fullName():string
}
class Player implements User {
constructor(
public firstName:string,
public lastName:string,
){}
fullName() {
return ${this.firstName} ${this.lastName}
;
}
sayHi(name) {
return Hello ${name}! My name is ${this.fullName()}
;
}
}
> - **클래스가 인터페이스 구현**시 `implements` 키워드 사용.
> - 객체에 인터페이스 적용시 `:` 으로 작성하면 됨.
interface를 사용한 경우 프로퍼티를 모두 구현해야 한다.
🔻 JS 코드
``` js
"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()}`;
}
}
아까는 인스턴스를 만들수도 없는 쓸모없는 User 클래스가 Js 코드에 존재했었지만,
이번에는 인터페이스를 사용했으므로 위와 같이 짧은 코드가 되었다. 👍
🔻 또한 하나 이상의 인터페이스를 상속받을 수 있다.
interface User {
// 내용
}
interface Human {
// 내용
}
class Player implements User, Human {
constructor(){}
}
클래스를 타입으로 쓸 수 있듯이, 인터페이스도 타입으로 사용할 수 있다.
interface User {
firstName: string,
lastName: string,
sayHi(name:string):string
fullName():string
}
function makeUser(user:User): User {
return {
...
}
}
makeUser({
firstName: 'yjin',
lastName: 'lee',
fullName: () => "yjin lee"
sayHi: (name) => "string"
implements
를 써야 함.extends
를 써야 함.interface는 확장시 클래스처럼 extends를 사용함.
type과 interface는 모두 class에 상속해서 쓸 수 있음
type PlayerA = {
firstName: string
}
interface PlayerB {
firstName: string
}
class User implements PlayerA {
constructor(public firstname:string){}
} // type도 implements로 상속함
class User implements PlayerB {
constructor(public firstname:string){}
}
🙋♂️ 언제 어떤 것을 사용할까?
- object의 모양을 알려줄 때는 - Interface
- 나머지 상황에서는 - Type Aliases
+) 확장을 해야하는 상황에서는 인터페이스가 편리함.
= 다형성
다른 모양의 코드를 가질 수 있게 함.
제네릭(Generic)을 사용함. -> type의 placeholder 역할.
concrete 타입을 사용하기 애매한 경우 generic으로 placeholder type을 지정하고, 때가 되면 concrete type이 되게 함.
// 이미 Storage라는 인터페이스가 존재함. (localStorge 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 stringStorage = new LocalStorage<string>()
const numberStorage = new LocalStorage<number>()
<T>
는 generic(제네릭)으로, 이는 인터페이스에게 물려줄수도 있다.
LocalStorage 에서 <T>
를 선언한 후,
SStorage(=인터페이스)에도 붙여주어 해당 값을 물려줄 수 있다.
-> SStorage 에서는 받아온 제네릭을 사용한다.