인터페이스와 클래스

타입 스크립트 시리즈 3탄!

인터페이스와 클래스에 대한 내용을 다뤄보겠습니다.

인터페이스

앞서 타입에 대한 글을 보셨다면 타입 계층도가 있다는 걸 아실 겁니다.

그중 Object 타입은 인터페이스와 클래스 타입의 상위 타입입니다.

즉, Object로 선언된 변수는 class나 interface 둘 다 저장이 가능해집니다.

물론 number, boolean, string 타입의 값은 넣을 수 없습니다.

let o: object = {name: 'cent', age: 100}
o = {title: 'name is good', description: 'hahahaha'}

위 코드는 object 타입이 any처럼 다른 클래스 값을 저장합니다. 이것을 막기 위해 인터페이스을 채택 했습니다.

즉, 위 코드처럼 속성이 바뀌는 것이 아닌 name과 age 속성을 가진 값만 가져올 수 있도록 정의합니다.

인터페이스 선언문

앞서 말씀드린 대로 인터페이스를 선언하기 위해 interface 키워드를 사용합니다.

아래 코드를 보시죠.

interface name {
	propertyName: type
}

위 코드가 기본 코드 템플릿입니다.

// 인터페이스 구문 예시
interface IAnimal {
	name: string
	age: number
}

해당 객체의 형식만 유용하도록 interface를 정의했습니다.

보통 인터페이스를

사용법은 아래 코드로 설명할 수 있습니다.

let animal: IAnimal = {name: 'dog', age: 10}
let error1: IAnimal = {name: 'bird'} // error
let error2: IAnimal = {age: 1} // error
let error3: IAnimal = {} // error
let error4: IAnimal = {title: 'Hi!'} // error

이렇듯 변수를 명확하게 정의하기 위해서는 인터페이스를 사용하면 좋습니다.

타입 스크립트 시리즈 2를 보시면 왜 이렇게까지 타입에 엄격한지 알 수 있습니다.

선택 속성 구문과 익명 인터페이스

인터페이스를 설계할 때 모든 속성이 있어야만 정의가 됩니다.

하지만 어떤 속성은 선택에 따른 속성 부여를 하고 싶을 수도 있습니다.

그럴 때 사용하는 것이 선택 속성 구문입니다.

쉽게 정의할 수 있으며, 아래 예시를 통해 사용법을 알아보겠습니다.

interface IAnimal2 {
	name: string
	age: number
	habitat?: string // 선택 속성
	etc?: string   // 선택 속성
}
let animal: IAnimal2 = {name: 'dog', age: 5}
let animal1: IAnimal2 = {name: 'cat', age: 2, habitat: 'home'}

속성 명 뒤에 물음표(?)을 넣으면 선택 속성 구문으로 처리됩니다.

속성 값을 넣어도 되고 안 넣어도 문제없이 동작합니다.

그다음은 익명 인터페이스입니다. 익명 인터페이스는 interface 키워드를 사용하지 않고, 이름도 없는 인터페이스 입니다. 사용 방법은 아래 코드로 설명합니다.

let human: {
	name: string
	age: number
	height: number
	etc?: string
} = {name: 'cent', age: 10, height: 180, etc: 'tired'}

익명 인터페이스는 함수를 구현할 때 사용됩니다.

function func(human: {name: string, age: number, height: number, etc?: string}) {
	console.log(`Hi Human. Your name is ${human.name}`)
	console.log(`And your age is ${human.age}`)
}
func(human)

이와 같이 활용할 수 있습니다.

한번 쓰고 끝낼 변수를 활용할 때 유용합니다.

지속적으로 사용될 인터페이스는 앞서 정의한 대로 따로 정의하는 것이 좋습니다.

클래스

클래스는 우리가 흔히 알고 있는 객체 지향 언어에서 사용되는 클래스와 동일합니다.

구현체이며 인터페이스를 상속받을 수 있습니다.

접근 제한자를 제공하고 생성자 또한 제공합니다.

하나씩 알아보죠

class Human {
	name: string
	age?: number
	etc?: string
}
let cent: Human = new Human()
cent.name = 'cent'
cent.age = 10
console.log(cent) // Human { name: 'cent', age: 10}

위와 같이 클래스를 선언할 수 있습니다.

가장 간단한 형태이며 여러 키워드를 추가할 수 있습니다.

하나씩 확인해보겠습니다.

private class Human2 {
	name: string
	age?: number
	etc?: string
	constructor(public name: string, public age?: number, etc?: string) {}
}
let cent2: Human2 = new Human2('cent', 15)
console.log(cent2) // Human2 { name: 'cent', age: 15 }

private, public과 같은 접근 제한자는 전부 제공합니다. 여기서 사용되지 않은 protect도 제공합니다.

또한 생성자는 constructor 키워드로 위와 같이 선언할 수 있습니다.

인터페이스 구현

interface IHuman1{
	name: string
	age?: number
}
class Human1 implements IHuman1 {
	name: string
	age: number
}
class Human2 implements IHuman1 {
	constructor(public name: string, public age?: number) {}
}
let human: IHuman1 = new Human2('cent', 21)
console.log(human) // Human2 { name: 'cent', age: 21 } 

코드를 보면 클래스에 implements 키워드를 통해 인터페이스를 구현했습니다.

객체 지향 언어를 알고 계신다면 익숙한 코드이며, 모르는 분에게는 생소할 수 있습니다.

인터페이스는 코드의 설계를 담당하고 클래스는 설계된 인터페이스를 구현한다라고 알고 계시면 됩니다.

implements 키워드를 통해 다양한 클래스에 인터페이스를 상속해서 통일성 있는 클래스를 만들 수 있습니다.

추상 클래스

abstract class AbstractHuman {
	abstract name: string
	age: number
	constructor(name: string, age: number) {}
	abstract methodName() {}
}

위 코드를 보면 처음 보는 키워드가 있습니다.

abstract 키워드입니다.

추상 클래스에 대한 설명부터 하면 인터페이스에 구현까지 가능한 클래스라고 보면 됩니다.

상속하기 위한 클래스이며, 기존 클래스처럼 구현체도 함께 존재합니다.

추상 클래스이기 때문에 new 연산자를 통해 객체를 만들 수 없습니다.

클래스 상속

클래스는 대체로 인터페이스를 상속하지만 클래스 자체도 상속이 가능합니다.

클래스 상속은 extends라는 키워드를 사용해 상속합니다.

class Human extends AbstractHuman {
	constructor(public name:string, age: number, etc?: string) {
		super(name, age)
	}
}
let human: Human = new Human('cent', 22)
console.log(human) // Human { name: 'cent', age: 22 }

위 코드를 보면 왜 클래스 상속과 같은 것을 사용하는지 이해가 안 될 수 있습니다.

가장 큰 이유는 중복된 코드를 작성하지 않는 것입니다.

그다음은 어느 정도 설계된 객체를 가져와 확장해서 사용할 수 있기 때문입니다.

지금은 클래스 하나에 상속하고 있지만 여러 개의 클래스에도 동일한 옵션들이 들어간다면 인터페이스나 추상 클래스를 사용해 코드를 합치고 개선할 수 있습니다.

또한, 라이브러리를 만들 때 다른 사람들이 상속을 통해 기능을 확장하고, 새로운 기능을 정해진 틀 안에서 작성할 수 있게 됩니다.

그렇기 때문에 상속과 관련된 기능들은 중요합니다.

특히 인터페이스는 캡슐화라는 클래스 구현부 감추기에 탁월한 기능을 하고 있기 때문에 이 내용은 객체지향 프로그래밍을 공부하면 좋습니다.

static 속성

static 속성은 정적인 속성을 의미합니다. 객체지향 언어에서 지원하기 때문에 타입 스크립트도 지원합니다.

아래 코드를 보죠.

class Human {
	static val = 1
}
let stVal = Human.val // 1

위와 같이 사용이 가능합니다.

static은 선언과 동시에 메모리에 값이 저장되고, 정적 속성을 가지고 있기 때문에 클래스를 인스턴스를 생성하지 않고도 사용이 가능합니다.

함께 보면 좋은 글

객체와 타입 – 타입스크립트 시리즈 2

참고

짤막글-Interface와-Class의-차이점

Leave a Comment