typescript에서 사용 가능한 interface기능을 공부하고 어떻게 활용하는지 알아보자.
let use:object;
user = {
name: 'Tom',
age: 30
};
console.log(user.name);
위 코드를 실행해보면 user.name
의 name쪽에 에러가 발생한다. 그 이유는 user가 object인 것은 알지만 그 안의 property(프로퍼티)값의 타입은 지정되지 않아 모르기 때문이다.
이럴 때 property를 정의해서 사용하고자 한다면 interface
를 이용하면 된다.
interface User {
name: string;
age: number;
}
위와 같은 방식으로 User라는 객체 형태의 타입을 만들어줄 수 있고, 이 안에는 해당 객체가 가질 수 있는 프로퍼티와 그에 대한 타입이 지정되어 있다.
이는 아래와 같이 사용된다.
let user1:User = {}; // Error
let user2:User = {
name: 'Tom',
age: 30
}
위 코드에서 user1
은 User가 타입으로 지정되었고 객체이지만 에러가 뜬다. 그 이유는 name과 age 프로퍼티를 지니지 않았기 때문이다.
아래 코드를 작성해보면 let user
에 밑줄이 가며 에러가 뜬다. 이유는 interface
에서 User는 gender라는 프로퍼티까지 지닌다고 설정해두었는데 let user
에는 gender 프로퍼티가 작성되지 않았기 때문이다.
// 옵션 미지정시
interface User {
name: string;
age: number;
gender: string;
}
let user:User = {
name: 'Tom',
age: 30
}
그렇다면 만약 어떠한 프로퍼티값은 지닐 수도 있고 아닐 수도 있게 지정하고 싶다면 어떻게 해야할까? 아래와 같이 ?
만 붙여주면 된다.
interface User {
name: string;
age: number;
gender?: string; // 옵션으로 지정
}
let user:User = {
name: 'Tom',
age: 30
}
이번엔 읽어오는 것만 가능하고 수정은 불가한 read only를 만들어보자.
아주 간단히 앞에 readonly
만 붙여주면 된다.
interface User {
name: string;
age: number;
gender?: string;
readonly birthYear: number; // 읽어오기 전용
}
let user:User = {
name: 'Tom',
age: 30,
birthYear: 1999
}
user.birthYear = 2002; // 수정불가이기 때문에 에러
이러면 생성시에만 부여가 가능하고 이후 수정은 불가하다.
Question
1. 만약 객체의
{key: value}
가 갖는 값은 다르지만 type은 동일한 프로퍼티를 여러개 지닐 수 있도록 하고 싶다면?
ex) {a: 2, b: 5} -> 각각이 {string: number}로 같은 유형을 지님2. 이러한 key들의 타입은 알되 정확히 어떤 내용이 작성될지 모를 때엔?
ex) key는 number, value는 string이 확실한데, key에 뭐가 들어가지? 1? 2?3. 그리고 프로퍼티는 optional하게 하여 각 interface로 만들어진 객체마다 다르게 작성하고 싶다면?
이 때 사용하는 것이 인덱스 서명이다.
interface User {
name: string;
age: number;
gender?: string;
readonly birthYear: number;
[grade: number]: string;
}
이렇게 하면 위에서 확인할 수 있듯이 key를 number로 가지고, value를 string을 가지는 프로퍼티를 여러개 가질 수도 있고, optional하기 때문에 작성하지 않을 수도 있다.
참고:
grade
라는 건 사용자정의이므로 아무렇게 작성 가능하다.['example': number]: string;
이러한 interface는 객체 뿐 아니라 함수에서 인수를 지정하는 데에도 사용할 수 있다.
interface Add {
(num1: number, num2:number): number;
}
이때 (num1: number, num2:number):
뒤에 작성된 number는 return값
에 대한 지정으로, 만약 return이 없다면 void
로 지정해주면 된다.
그리고 이때 작성한 num1, num2라는 인수의 이름은 사용자정의로 사용할 수 있다.
const add: Add =function(x,y) {
return x+y;
};
add(10,20); // Run
add(10,'20'); // Error
interface IsAdult {
(age:number): boolean;
}
const verifying: IsAdilt = (age) => {
retunr age > 19;
}
verifying(30); // true
verifying(15); // false
interface를 이용해 Class
를 정의하는 것도 가능하다. 아래에 작성된 Car라는 interface를 통해 알아보자
interface Car {
color: string;
wheels: number;
start(): void;
}
class Bmw implements Car {
a = 3;
}
이렇게만 작성하면 오류가 뜬다. 사진처럼 오류가 뜨고, interface Car에 맞는 값이 없다고 한다. 그렇다면 이에 맞는 속성값들을 넣어주자.
class Bmw implements Car {
color: 'red';
wheels: 4;
start() {
console.log('go!');
};
}
오류없이 잘 작동한다. 이제 여기에 Class답게 constructor도 넣어주도록하자. 이때 color에 대한 값은 받아오게 만들자.
class Bmw implements Car {
color;
constructor (c:string) {
this.color = c;
}
wheels = 4;
start() {
console.log('go!');
}
};
const b = new Bmw('green');
위 코드를 작성하면 컴파일 과정을 거쳐 아래와 같은 JS 코드가 된다.
또한 interface를 extends
를 이용해 확장해서 사용하는 것도 가능하다. 위의 예시 코드를 이용해 만들어보면,
interface Car {
color: string;
wheels: number;
start(): void;
}
interface Audi extends Car {
sheet: number;
stop(): void;
}
이같이 Car라는 interface를 확장해서 sheet와 stop()이라는 속성을 지닌 새로운 Audi라는 interface를 만들었다.
Audi는 Car를 확장한 것이기 때문에 Car의 속성도 모두 지니게 작성되어야 한다.
extends
는 여러개를 한번에 하는 것도 가능하다.
interface Car {
color: string;
wheels: number;
start(): void;
}
interface Engine {
horsepower: number;
}
interface Supercar extends Car, Engine {
sheet: number;
stop(): void;
}
이렇게 하면 Supercar라는 interface는 Car와 Engine 모두의 속성을 지니며 sheet와 stop()이라는 속성도 가지게 된다.
P.S. interface를 공부하다보니 계속 추가적으로 꼬리물기처럼 더 궁금한 것, 알아야할 것들이 생긴다.
호기심 넘치는데 동시에 머리 터지겠다..🤯