
constructor를 작성하면, js로 컴파일 후 자동으로 this. 가 생성된다.
private, public은 js에 없지만 ts에서 사용하면 컴파일 전에 확인 가능하다.
class Player {
constructor(
private firstName: string,
private lastName: string,
public nickName: string
) {}
}
const nico = new Player("nico", "las", "니꼬")
Abstract Class
추상클래스는 다른 클래스가 상속받을 수 있는 클래스다.
직접 새로운 인스턴스를 만들 수 없다.
다른 곳에서만 상속받을 수 있는 클래스다.
private: property들은 당연히 인스턴스 밖에서 접근할 수 없고, 다른 자식 클래스에서도 접근할 수 없다.
protected: property들은 인스턴스 밖에서는 접근할 수 없고, 다른 자식 클래스에서는 접근할 수 있다.
abstract class User {
constructor(
private firstName: string,
private lastName: string,
public nickName: string
) {}
abstract getNickName(): void
getFullName() {
return `${this.firstName} ${this.lastName}`
}
}
class Player extends User {
getNickName() {
console.log
}
}
const nico = new Player("nico", "las", "니꼬")
abstract method
argument를 받을 경우 이름, 타입, 함수의 리턴타입을 정의한다.
abstract class를 상속받는 클래스에서 abstract method를 구현해주어야 한다.
public, private, protected
public: 기본값, 어디서든 접근가능
private: 해당 클래스에서만 접근가능
protected: 해당 클래스, 자식클래스에서 접근가능
type Words = {
[key: string]: string // key와 value 값이 string이어야 한다.
}
class Dict {
private words: Words
constructor(){
this.words = {}
}
add(word: Word) { // class를 이용해서 type로 쓸 수 있다!!!!
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,
public readonly def: string,
) {}
}
const kimchi = new Word("kimchi", "한국의 음식");
const dict = new Dict();
dict.add(kimchi);
dict.def("kimchi");
interface는 object의 모양을 결정할 때만 사용한다.
type를 사용할 수 있지만 type는 object 뿐만 아니라 다른 값을 결정할 때도 사용할 수 있다.
interface를 사용하는 게 클래스를 사용하는 느낌과 비슷해서 더 쉽다.
type Team = "red" | "blue" | "yellow"
type Health = 1 | 5 | 10
interface Player {
nickname: string,
team: Team,
health: Health
}
type Player = {
nickname: string,
team: Team,
health: Health
}
const nico: Player = {
nickname: "nico",
team: "yellow",
health: 10
}
interface User {
name: string
}
interface Player extends User { // User를 상속받을 수 있다.
}
const nico: Player = {
name: "nico"
}
// type를 사용한다면 다음과 같이 쓸 수 있다.
type User = {
name: string
}
type Player = User & {
}
const nico: Player = {
name: "nico"
}
interface는 객체 지향 프로그래밍의 개념을 활용해서 디자인되었다.
각각 만들어도 타입스크립트가 알아서 하나로 합쳐준다. type는 안됨.
interface User {
name: string
}
interface User {
lastName: string
}
interface User {
health: number
}
interface와 type는 상속하는 방법이 다르다.
abstract class는 상속받는 다른 클래스가 가질 property와 method를 지정한다.
// 다른 클래스가 따라야 할 청사진(설계도)만을 제시했을 뿐이다.
// User class를 상속한다면 sayHi, fullName을 구현해야 한다.
// abstract class가 js에서는 일반적인 클래스로 바뀐다.
abstract class User {
constructor(
protected firstName: string,
protected lastName: string
) {}
abstract sayHi(name: string): string
abstract fullName(): string
}
class Player extends User {
fullName() {
reuturn `${this.firstName} ${this.lastName}`
}
sayHi(name: string) {
return `Hello ${name} My name is ${this.fullName}`
}
}
interface는 typescript에서만 존재하고, js로 컴파일되지 않기 때문에 존재하지 않는다.
class가 아니지만 class의 모양을 특정할 수 있기 때문에 유용하다!!
interface User {
firstName: string,
lastName: string
sayHi(name: string): string
fullName(): string
}
interface Human {
health: number,
}
class Player implements User, Human { //2개의 interface를 implement할 수 있다!
constructor(
public firstName: string, //interface에서는 public이 되어야만!
public lastName: string,
public health: number,
) {}
fullName() {
reuturn `${this.firstName} ${this.lastName}`
}
sayHi(name: string) {
return `Hello ${name} My name is ${this.fullName}`
}
}
type과 interface의 차이점
ts에게 object의 모양과 타입을 알려주는 게 목표라면, type와 interface 둘 다 사용 가능하다. 하지만 둘을 사용해서 할 수 있는 것들이 다르다.
type는 변수명을 중복해서 쓸 수 없고,
interface는 변수명이 중복해서 추가로 사용할 수 있다. 즉, interface 정의를 합칠 수 있다!
// type
type PlayerA = {
name: string
}
type PlayerAA = PlayerA & {
lastName: string
}
const playerA: PlayerAA = {
name: "nico"
lastName: "xxx"
}
// interface
interface PlayerB {
name: string
}
interface PlayerB {
lastName: string
}
interface PlayerB {
health: number
}
const playerB: PlayerB = {
name: "nico",
lastName: "xxx",
health: 1
}
type, interface 모두 추상 클래스를 대체해서 사용할 수 있다.
클래스나 오브젝트의 모양을 정의하고 싶으면 interface를 사용하고, 다른 경우에는 type를 많이 사용한다.
type PlayerA = {
firstName: string
}
interface PlayerB {
firstName: string
}
class User implements PlayerB { // PlayerA를 사용해도 무방
constructor(
public firstName: string
) {}
}
T라고 불리는 Generic을 Class로 보내고,
Class는 Generic을 interface로 보낸 뒤에,
interface는 Generic을 이용한다.
LocalStorage API를 따라해보자.
interface SStorage<T> {
[key: string]: T
}
class LocalStorage<T> { // T라고 불리는 Generic을 받을 계획이다.
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>();
// generic을 바탕으로 call signature를 만들어준다.
// typescript가 concrete type으로 바꿔준다!
stringStorage.get("key");
stringStorage.set("hello", "how are you");
const booleanStorage = new LocalStorage<boolean>();
booleanStorage.get("XXX");
booleanStorage.set("hello", true);