티스토리 뷰
▶타입스크립트 인터페이스(interface)
타입스크립트는 매번 선언하는 변수 혹은 함수의 파라미터로 들어가는 변수에 대해서
반드시 타입을 정의해 주어야만 했습니다.
그런데 우리가 프로젝트를 진행하다보면 서로 다른 함수에 똑같은 인자를 넘겨주는 경우가 많은데요.
이때는 매번 반복적으로 작성을 해주어야 하는 걸까요?
이러한 반복되는 작업에 대해서는 인터페이스라는 것을 통해 코드를 좀 더 간결하고 깔끔하게 작성 가능합니다🤩
🔎 인터페이스란?
인터페이스는 미리 정의한 약속 혹은 규칙을 의미합니다.
타입스크립트에서의 인터페이스는 다음과 같은 부분에서 사용이 가능합니다.
- 객체의 스펙(속성과 속성의 타입)
- 함수의 파라미터
- 함수의 스펙(파라미터, 반환 타입 등)
- 배열과 객체를 접근하는 방식
- 클래스
간단하게 인터페이스 사용해 보기
우선 가장 먼저 User 라는 이름의 인터페이스를 하나 정의해 줄 겁니다.
따라서 이 User 라는 인터페이스를 사용하는 얘는 무조건 age: number, name: string을 가져야 한다는 말입니다.
interface User {
age: number;
name: string;
}
변수에 User 인터페이스를 적용해 보겠습니다.
var seho: User = {
age: 33,
name: '세호',
};
위와 같이 적용하면 되겠습니다.
만약 우리가 미리 약속한 User 인터페이스와 맞지 않게 변수를 정의하게 되면 당연히 에러를 내겠죠?
age를 주석처리 해 보았더니 에러가 발생했습니다.
에러가 발생한 곳에 마우스를 갖다 대 보았더니 바로 age가 없다고 알려주고 있는 것을 확인할 수 있었습니다.
🔎 함수에서의 인터페이스
함수의 파라미터에게도 인터페이스를 적용할 수가 있습니다.
앞서 정의한 User 인터페이스를 활용해 보겠습니다.
// 함수에 인터페이스 활용
function getUser(user: User) {
console.log(user);
}
const doeun = {
name: '도은',
age: 22,
};
getUser(doeun);
위와 같이 함수를 정의하게 되면 getUser 함수를 사용할 때 들어가게 되는 인자 user는
무조건 age: number, name: string을 가지고 있어야만 한다는 말입니다.
옵션 속성
타입스크립트 함수 때 옵셔널 파라미터라는 것을 알아보았었습니다.
복습을 해보자면, 파라미터 이름 뒤에 물음표(?)를 붙임으로써 함수를 사용할 때
물음표가 붙은 파라미터에 대해서는 인자를 선택적으로 넘겨주거나 넘겨주지 않거나 하는 것이 가능했습니다.
이러한 옵셔널적인 성질은 인터페이스에서도 적용이 가능합니다.
// 옵션 속성
interface Info {
name: string;
phone?: string;
}
위와 같이 물음표를 붙인 옵션 속성에 대해서는 선택적으로 작성이 가능하게 됩니다.
함수의 스펙(구조)에서의 인터페이스
함수의 스펙(구조)는 함수에 인자로 넘겨주는 파라미터와 반환값을 전부를 의미합니다.
이러한 스펙에 대해서도 한번에 인터페이스로 정의하여 넘겨주는 것도 가능합니다.
interface SumFunction {
(a: number, b: number): number,
}
위 코드에 대해 이야기 해보자면
이 인터페이스를 적용받을 함수는
무조건 인자로 a: number, b: number (들어가는 인자 이름에 대해서는 당연히 코드에 따라 달라질 수 있습니다)
반환값은 number가 되어야 한다는 말과 같습니다.
SumFunction 인터페이스를 활용해 봅시다!
var sum: SumFunction;
sum = function(a: number, b: number): number {
return a + b;
}
만약 약속한 함수의 스펙과 다르게 사용하면 당연히 에러를 띄워주겠죠? 아래와 같이요.
위 코드에서 a: number → a: string으로 변경해 보겠습니다.
그러면 위와 같이 a가 number 형식이여서 string 형식을 할당할 수 없다고 알려주게 되는 것을 확인할 수 있었습니다.
🔎 배열에서
배열 안에 들어가는 성분들도 타입을 정의할 수 있습니다.
만약 배열을 인덱싱하여 지정한 타입과 다른 타입의 변수를 집어넣을 경우 에러가 띄워지겠죠?
interface StringArray {
[index: number]: string;
}
위 코드에 대해 이야기 해보면,
StringArray 인터페이스를 적용받는 배열에 대해서 내부 성분들은 모두 string 타입을 가져야 하는 것을 의미합니다.
마찬가지로 인덱싱하여 값을 변경할 때에도 string으로만 변경이 가능합니다.
인덱싱을 하여 number 타입으로 값을 변경하려고 하니 에러가 발생한 것을 확인할 수 있었습니다.
🔎 객체에서
객체 패턴
객체에 들어가는 key와 value에 대해서도 인터페이스를 통해 약속을 할 수가 있습니다.
interface StringRegexDictionary {
[key: string]: RegExp;
}
이때 RegExp는 Regular Expression으로 정규표현식을 의미합니다.
간단하게 말하면 문자열에서 특정 내용을 찾거나 대체 또는 발췌하는데 사용을 하는 건데요.
위 코드에서는 StringRegexDictionary 인터페이스를 적용받는 객체에 대해서는
모든 key는 string 타입이면서 정규표현식의 value를 가져야 한다!를 의미하게 됩니다.
var obj: StringRegexDictionary = {
sth: /abc/, // 정규식 -> obj.sth으로 바로 접근 가능하게 해줌
cssFile: /\.css$/, // css 확장자를 가진 모든 파일을 가져오는 정규식
jsFile: /\.js$/,
};
객체 패턴을 약속하면 좋은 점
객체에 들어갈 key와 value의 타입을 정의해 주게 되면 좋은 점을 알아보겠습니다.
예를 들어 설명해 보면,
객체로 담겨있는 사용자 정보를 받아와서 그 키값을 이용해 처리하는 경우를 빈버하게 볼 수가 있는데요.
이때 키값이 딱 string이다라고 약속하게 되면 다음과 같이 그 타입에 맞게 적용할 수 있는 함수들을 바로 확인이 가능합니다.
위에서 우리가 정의한 obj의 키값은 string 타입으로 약속했었기 때문에
string 타입에 적용할 수 있는 함수들을 위와 같이 보여주게 되며 이는 오류를 피하는 좋은 방법이기도 합니다.
만약에 위 코드에서 들어오는 value가 무슨 타입인지를 모르면
저렇게 적용할 수 있는 함수를 애초에 알려줄 수가 없고
이는 모두 개발자가 원하는 코드를 오탈자 없이 작성해야 하는 부담으로 이어지게 됩니다.
잘못 입력하게 되면 빨간줄도 없이 하루종일 오탈자를 찾게 되는 일도 발생할 수 있겠죠?...악
🔎 읽기 전용 속성 - readonly
읽기 전용 속성은 인터페이스로 객체를 처음 생성할 때만 값을 할당하고
그 이후에는 변경할 수 없는 속성을 의미합니다.
interface CreateUser {
readonly name: string;
}
즉, CreateUser 인터페이스를 적용받는 변수는 name을 한번 정의하고나면 수정할 수 가 없다! 와 같은 말입니다.
위와 같이 readonly로 정의한 속성을 불러 수정하려고 하면 에러를 띄우게 됩니다.
읽기 전용 배열 - ReadonlyArray<type>
위와 비슷하게 ReadonlyArray로 정의된 배열은 정의된 이후로는 수정이 불가합니다.
let ar: ReadonlyArray<number> = [1, 2, 3];
이렇게 정의하게 되면 ar 배열을 수정하려고 시도하면 다 에러가 발생하겠죠? 아래와 같이요!
🔎 객체 선언과 관련된 타입 체킹
타입스크립트는 인터페이스를 이용하여 객체를 선언할 때 좀 더 엄밀한 속성 검사를 진행하는데요.
interface CreateBook {
name?: string;
}
function makeBook(book: CreateBook) {
// ..
}
위와 같이 CreateBook 인터페이스를 정의해서 makeBook 함수의 인자에게 적용해 주었습니다.
그말은 곧, makeBook 함수를 사용할 때 인자로 name?: string을 적용하거나 적용하지 않아도 좋다고 하는 것과 같은 말입니다.
그래서 다음과 같이 일부러 오탈자를 내 보았더니 에러가 발생한 것을 볼 수 있습니다.
만약 이런 타입 추론을 무시하고 싶다면 아래와 같이 선언하면 됩니다.
let myBook = { namee: 'hello' };
makeBook(myBook as CreateBook);
만약 그럼에도 불구하고 마음대로 속성을 추가하여 사용하고 싶다면 아래와 같이 인터페이스를 작성해 주면 됩니다.
interface CreateBook {
name?: string;
[propName: string]: any; // 맘대로 속성을 추가하여 사용하고 싶을 때
}
🔎 인터페이스 확장
만약 인터페이스와 인터페이스끼리 중복되는 부분이 있다면 이 부분을 상속을 받아 확장하는 것이 가능합니다.
interface Person {
name: string;
age: number;
}
interface Developer extends Person {
// name: string;
// age: number;
language: string;
}
위와 같이 작성하면 Developer 인터페이스가 Person 인터페이스를 상속받아
Developer 인터페이스도 name: string과 age: number 속성을 사용하게 됩니다.
'프론트엔드 > TypeScript' 카테고리의 다른 글
[TypeScript] 타입스크립트 타입 추론(Type Inference) (0) | 2023.01.02 |
---|---|
[TypeScript] 타입스크립트 타입 별칭(Type Aliases) (0) | 2023.01.02 |
[TypeScript] 타입스크립트 함수 타입 - 파라미터, 반환값 (0) | 2022.12.28 |
[TypeScript] 타입스크립트 기본타입 - 튜플, 객체, 진위값 (0) | 2022.12.28 |
[TypeScript] 타입스크립트 기본타입 - 문자열, 숫자, 배열 (0) | 2022.12.28 |
- Total
- Today
- Yesterday
- frontend
- 자바스크립트 기초
- Python
- 자바
- next.js
- jest
- 파이썬
- 딥러닝
- 자바스크립트
- 프론트엔드 기초
- styled-components
- 리액트 훅
- 타입스크립트
- JSP
- 인프런
- CSS
- TypeScript
- 스타일 컴포넌트 styled-components
- 프로젝트 회고
- 리액트
- testing
- react
- rtl
- 데이터분석
- HTML
- 디프만
- react-query
- 프론트엔드
- 프론트엔드 공부
- 머신러닝
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |