[TypeScript] 인터페이스
인터페이스
- 앞서 배운 타입 별칭의 개념을 비교하며 살펴본다.
- 타입 별칭으로 지정할 수 있는 객체 → 인터페이스로도 설정 가능
- 따라서, 객체 타입만이 인터페이스로 설정 가능 (원시 타입 불가!)
interface키워드를 사용하여, 지정예시
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
// 객체 타입을 지정 시 사용 (나만의 객체 타입) interface User { name: string; age: number; } const user1: User = { name: "jaegeon", age: 20, }; ------------------------------------------- interface User { name: string; age: number; greet(): void; } const user1: User = { name: "jaegeon", age: 26, greet() { console.log(`${this.name}, ${this.age}`); }, }; user1.greet();
인터페이스 특징
타입 별칭과 달리, 상세 스펙이 보이지 않음.
타입 별칭과 달리, 인터페이스명 중복 가능.
⇒ 이름이 같다면, 자동으로 합쳐줌. (선언 병합)→ 주의사항: 인터페이스 내의 각 속성의 타입이 달라서는 안된다!
인터페이스 - 함수
함수를 인터페이스로 지정하면 다음과 같다.
1 2 3 4 5 6 7 8 9
// 함수 별칭의 경우 type SumFunc = (n1: number, n2: number) => number; // 인터페이스로 함수 정의 interface SumFuncInterface { (n1: number, n2: number): number; } const sum: SumFuncInterface = (n1, n2) => n1 + n2;
→ 주의사항: 인터페이스로 지정한 함수에는 옵셔널 파라미터 ?를 지정할 수 없다.
함수를 지정 시에,
name과 같은 함수에 원래 존재하는 속성을 사용 가능!1 2 3 4 5 6 7 8 9 10
// 함수 별칭의 경우 type SumFunc = (n1: number, n2: number) => number; // 인터페이스로 함수 정의 interface SumFuncInterface { name: string; (n1: number, n2: number): number; } const sum: SumFuncInterface = (n1, n2) => n1 + n2;
함수에 원래 존재하는 속성들 (
caller는 안됨!)
인터페이스 상속
- 자바스크립트(타입스크립트)에서 인터페이스를 상속할 수 있음
extends키워드를 사용하여, 상속을 표현- 문법적으로도, 인터페이스 상속 > 타입 별칭 & 용이.
- 공통으로 들어가는 부분을 각각의 인터페이스 사용할 때 용이.
예시
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
interface Animal { name: string; } interface Dog extends Animal { bark(): void; // 왈왈 } const dog: Dog = { name: "퍼피", bark() { console.log("왈왈"); }, }; interface Cat extends Animal { bark(): void; // 냐옹 } const cat: Cat = { name: "냥이", bark() { console.log("냐옹"); }, };
다중 상속도 컴마로 구분하여 가능하다!
1 2 3 4 5 6 7 8 9 10 11 12 13 14
interface A { a: string; } interface B { b: number; } interface C extends A, B { c: boolean; } const cValue: C = { a: "a", b: 121, c: true, };
타입 별칭과 인터섹션 파라미터
&로도 유사하게 사용 가능!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
type A = { a: string; }; type B = { b: number; }; type C = A & B & { c: boolean; }; const cValue: C = { a: "a", b: 121, c: true, };
인덱스 시그니처
다음 코드는 옵셔널 파라미터
?를 사용하지 않으면 속성 삭제 불가
이외에, 속성 추가와 수정도 불가1 2 3 4 5 6 7 8 9 10
const obj: { name: string; age?: number; } = { name: "jaegeon", age: 26, }; obj.gender = "male"; delete obj.age;
인덱스 시그니처
- 범용적인 타입 지정 방식
앞선 문제의 해결책으로 인덱스 시그니처를 사용.
1 2 3 4 5 6 7 8 9
const obj: { [key: string]: string | number; } = { name: "jaegeon", age: 26, }; obj.gender = "male"; delete obj.age;
- 객체의 속성을 자유롭게 추가하거나 변경 가능!
단, 명확한 타입 명시는 불가!
따라서, 섞어서 사용하면 해당 문제를 해결할 수 있다.
1 2 3 4 5 6 7 8 9 10 11
const obj: { name: string; age: number; [key: string]: string | number; } = { name: "jaegeon", age: 26, }; const name1 = obj.name; name1.toUpperCase();
[참고] 헝가리안 표기법
다음과 같이, 식별자의 타입이 다르나, 이름이 같아서 문제 발생
따라서, 헝가리 출신 개발자가 다음과 같이, 식별자 작성법 제시.
타입을 밝혀서 이름을 짓는 헝가리안 표기법number: num → nNumstring: name → strNametype: User→ TUserinterface: User→ IUser→ But, 오늘날에는 위와 같은 방법 권장 X
이유: 식별자의 타입의 변동 가능성이 있음 → 잘못된 정보 제공 우려
→ 따라서, 오늘날에는 이름을 의미있게 지어주는게 추세이다.
구조적 타이핑
- 타입스크립트는 이름으로 구분하는 것이 아닌, 내부 구조로 구분함.
이름이 달라도 구조가 같다면, 상호 호환이 됨.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
type Car = { name: string; speed: number; }; type Vehicle = { name: string; speed: number; }; let car: Car = { name: "MBW", speed: 100 }; let vehicle: Vehicle = { name: "HONDA", speed: 200 }; function printValue(obj: Car) { console.log(`${obj.name}, ${obj.speed}`); } printValue(vehicle);
위와 같이, 이름이 달라도 내부 구조가 같아. 다른 타입의 이름을 사용해도 무방.
많은 속성과 적은 속성
다음과 같이,
name속성이 포함된 두 객체에서
더 많은 속성을 포함한 객체가 적은 속성을 포함한 객체로 할당될 수 있음!1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
type Car = { name: string; speed: number; }; type Vehicle = { name: string; }; let car: Car = { name: "MBW", speed: 100 }; let vehicle: Vehicle = { name: "HONDA" }; vehicle = car; // 많은 속성이 적은 속성의 객체로 할당 가능 console.log(vehicle); console.log(vehicle.speed); // 담겼어도, speed 속성은 Vehicle에 없으므로 출력 불가