-
[Typescript] 인터페이스(Interface)Front-End(Web)/Typescript 2021. 2. 22. 19:12반응형
이전 글에서부터, 타입의 커스터마이징에 대해 얘기하면서, 그리고 Type Aliase 를 공부하면서 Interface 가 종종 거론되었다.
타입의 유형화에 유리한 이 인터페이스에 대해 한번 알아보도록 하자.
💙 Interface 란?
인터페이스는 특정 자료형의 구조를 나타낸 일종의 커스텀 타입이다.
인터페이스는 Javascript같은 동적타입 언어환경에선 다뤄지지 않으나, 정적타입 언어인 Typescript는 타입검사가 요구되므로 이를 지원한다.
- Interface 문법 및 적용
'interface' 키워드를 통해 제작할 수 있다. 나머지는, 변수선언 문법과 유사하다.
* Interface 이름 첫 글자는 대문자로 시작하도록 한다. 다른 정적언어는 I+인터페이스명을 권장하나, 타입스크립트는 해당되지 않음
interface [인터페이스명] { ... }
인터페이스는 컴파일된 JS파일에선 확인할 수 없다. 즉, Typescript가 컴파일될 때, 인터페이스를 제외시키는 것이다.
interface StudentInfo { studentId: number, studentName: string, age: number, subject: string, graduated: boolean, } function getStudentMoreInfo(studentId: number): StudentInfo { return { studentId: 10, studentName: 'Taeng', age: 29, subject: 'Typescript', graduated: false, }; }
인터페이스 적용방법이다. StudentInfo 인터페이스를 제작한 뒤, 이를 getStudentMoreInfo() 함수 반환값의 타입으로 적용한다.
인터페이스는 해당 형태의 타입으로 반환되는 것을 강제한다. (타입 불일치, 필드 누락 등등 시 에러 발생)
- Interface vs Type Aliase
두 문법 모두, 기존의 타입들을 활용해 커스텀 타입을 만든다는 공통점이 있다.
앞의 타입에서 언급했듯, 둘의 차이는 Type Aliase는 필드추가 및 타입상속(&로 가능) 이 제한되나, Interface는 가능하다는 것이다.
// Interface interface ButtonInterface { onInit():void; onClick():void; } interface ButtonInterface { onToggle():void; // ButtonInterface 병함됨 } // Type Aliase type ButtonType = { onInit():void; onClick():void; } type ButtonType = { onToggle():void; // 오류: 'ButtonType' 식별자가 중복되었습니다. }
💙 Interface 추가 문법
1. 인터페이스의 메서드(method) 정의
메서드는 객체 내에서 생성된 함수이다. 역시 마찬가지로, 함수 타입선언 방식을 통해 인터페이스에 포함될 수 있다.
interface CommentBox { addComment (comment: string): string; addComment: (comment: string) => string; }
2. 선택적 프로퍼티(Optional Properties)
인터페이스에서 반드시 포함되지 않아도 되는 프로퍼티가 있을 것이다. 이를 설정하는 문법으로, '?' 기호를 키 뒤에 붙여주기만 하면 된다.
선택적 프로퍼티의 이점은, 인터페이스에서 반드시 필요하지 않은 프로퍼티를 구분하는 한편, 이에 대한 오류를 확인 가능하단 것이다.
interface StudentInfo { studentId: number, studentName: string, age: number, subject?: string, graduated: boolean, } function studyName(student: StudentInfo) :string { return hisSubject: string = student.subjet; // error! subjet 프로퍼티명 존재하지 않음 }
3. 읽기 전용 프로퍼티(Read-only Properties)
말 그대로 수정은 불가하고 읽기만 가능한 필드이다. 생성시 할당된 프로퍼티 값을 수정할 수 없다. 필드명 앞에 readonly 를 붙여준다.
interface StudentInfo { readonly studentId: number, studentName: string, age: number, subject?: string, graduated: boolean, } function modifyStudentInfo (student: StudentInfo): void { student.studentId = 40, // error! (읽기전용) student.graduated = true, }
4. 함수 타입 인터페이스
인터페이스는 함수 타입도 정의할 수 있다. 문법은, 중괄호 안에 (매개변수 타입): 반환값 타입; 형태로 만든다.
interface FunctionalInterface { (n: number): number; }
함수 타입 인터페이스를 미리 설정하면, 함수 선언시 별도의 타입설정이 불필요해진다.
// Before: 함수타입 설정 const factorial = (n:number): number => { if (n === 0) { return 0; } if (n === 1) { return 1; } return n * factorial(n - 1); } // After: 함수타입 인터페이스 interface FactorialInterface { (n: number): number; } const facto: FactorialInterface = (n) => { if (n === 0) { return 0; } if (n === 1) { return 1; } return n * facto(n - 1); };
5. 인덱서블 타입 인터페이스
인덱싱이 가능한 자료형을 의미한다. 문법은 대괄호 안에 [인덱스 타입]: 반환값 타입; 형태로 만든다.
이러한 기술법을, 인덱스 시그니쳐(Index Signature) 라고 한다. 인덱스 시그니쳐의 인덱스 타입은 number 혹은 string 이어야만 한다.
interface StringArray { [index: number]: string; } let myArray: StringArray; myArray = ["Bob", "Fred"]; let myStr: string = myArray[0];
* 이전의 객체 인터페이스에서, 프로퍼티 추가를 위해 작성했던 아래 예제도 인덱스 시그니처에 해당된다.
interface ButtonInterface { onInit?():void; onClick():void; // 인덱스 시그니처 [prop:string]: any; }
6. 클래스 타입 인터페이스, 인터페이스 확장
인터페이스는 클래스와 비슷하나, 정의만 할 뿐 실제 구현되지는 않는다. (일종의 추상 클래스)
클래스를 통해서 인스턴스를 생성했을 때, 이것이 가져야 할 속성 또는 메서드를 정의할 수 있는 것이다.
또한, 클래스의 extends 키워드로 하나의 클래스에 상속, implements 키워드를 통해 해당 인터페이스들을 클래스와 연결할 수 있다.
// 클래스 => 인터페이스 상속 class Control { private state: any; protected someState: any = 100; } interface SelectableControl extends Control { select(): void; } // 인터페이스 => 클래스 참조 interface ClockInterface { currentTime: Date; setTime(d: Date): void; } class Clock implements ClockInterface { currentTime: Date = new Date(); setTime(d: Date) { this.currentTime = d; } constructor(h: number, m: number) { } }
인터페이스 간에도 마찬가지로, extends(상속)을 통해 다양한 조합을 만들 수 있다.
// 인터페이스 확장 interface Shape { color: string; } interface Square extends Shape { sideLength: number; } // 인터페이스 다중 확장(복수) interface Shape { color: string; } interface Size { width: number; height: number; } interface DrawSquare extends Shape, Size {} let square = {} as DrawSquare; square.color = 'red'; square.width = 20;
Typescript의 클래스 문법에 대해서는 별도로 포스팅하며, 이전에 Javascript 클래스 공부가 선행되야 할 것 같다.
(Typescript 가이드북 링크 : yamoo9.gitbook.io/typescript/classes )
7. 하이브리드 타입
인터페이스는 Javascript의 다양한 타입들을 적용할 수 있으며, 이러한 프로퍼티들을 복합적으로 수행할 수 있다.
interface Counter { (start: number): string; interval: number; reset(): void; } function getCounter(): Counter { let counter = (function (start: number) { }) as Counter; counter.interval = 123; counter.reset = function () { }; return counter; } let c = getCounter(); c(10); // 함수역할 수행 (counter 함수) c.reset(); // 객체역할 수행: 메서드 프로퍼티 c.interval = 5.0; // 객체역할 수행: 숫자타입 프로퍼티
사실 Type Aliase와 근본적으로 큰 차이점이 느껴지진 않았다. 좀 더 세부적인 문법들로 구현할 수 있다는 차이점을 제외한다면?
인터페이스 공부도 의미있었지만, 클래스 관련 부분에서 많은 부분을 생략했다. (public, private 개념, 전역 프로퍼티, 추상 클래스 등)
이 부분을 별도로 공부하여 포스팅할 것이며, 이를 위해 Javascript ES6 클래스 자료형에 대한 공부부터 선행되어야 할 것 같다.
[출처]
- Typescript 핸드북 : typescript-kr.github.io/pages/basic-types.html#%ED%83%80%EC%9E%85-%EB%8B%A8%EC%96%B8-type-assertions
- Typescript 가이드북 : yamoo9.gitbook.io/typescript/types/type-assertions
- kjwsx23 님의 블로그 : kjwsx23.tistory.com/450?category=746259
반응형'Front-End(Web) > Typescript' 카테고리의 다른 글
[Typescript] 제네릭(Generic) (0) 2021.02.23 [Typescript] 유니언과 교차 타입 (0) 2021.02.23 [Typescript] 열거형(Enum) & Literal Type (0) 2021.02.23 [Typescript] 타입(Type) (0) 2021.02.22 [Typescript] Typescript 기초 및 설정 (0) 2021.02.22