인터페이스란?
- 자바스크립트에서는 사용하지 않는 타입스크립트 문법
- 변수 나 함수 , 그리고 클래스 가 만족해야하는 최소 규격을 지정할 수 있게 해주는 도구
인터페이스 기본 문법
- 타입 별칭과 동일한 타입을 지정하는 방법 중 하나로 c, java 의 인터페이스 처럼 작성하는 방법
- 선택적 프로퍼티, 읽기전용 프로퍼티가 가능하다.
- 매개변수, 반환값을 포함한 메서드 오버로딩 타입 지정도 가능하다.
- 대신, 별칭 처럼 | 연산자를 사용하여 인터페이스를 여러개 지정할 수는 없다.
// 인터페이스
interface Person {
readonly name: string;
age?: number;
sayHi(): void;
sayHi(a: number): void;
sayHi(a: number, b: number): void;
}
const person: Person = {
name: "kim",
sayHi: function () {
console.log("sayHi");
},
};
// person.name = "홍길동"; // error - 할당 값 수정 불가
person.sayHi();
// interface Person { // 인터페이스는 | 연산자로 타입 지정 안됨
// name: string;
// age: number;
// } | number
인터페이스 확장/상속
- 다른 인터페이스를 상속 받아 하나의 인터페이스로 프로퍼티를 정의하도록 도와주는 문법
- 프로퍼티 확장이 가능하다.
// 인터페이스 확장
interface Animal {
name: string;
age: number;
}
interface Dog extends Animal {
// name: number; // error - 타입 재정의는 불가
isBark: boolean; // 별칭 확장
}
interface Cat extends Animal {
isScratch: boolean;
}
interface Chicken extends Animal {
isFly: boolean;
}
interface DogCat extends Dog, Cat { // 다중 확장
}
인터페이스 합치기
- 동일한 이름의 인터페이스끼리 프로퍼티가 합쳐진다.
- 프로퍼티가 이름은 같지만 타입이 다른 경우 충돌이 발생하려 오류를 표출한다.
// 인터페이스 합치기
interface Person {
name: string;
}
interface Person {
// name: number; // error - 프로퍼티가 중복되는 별칭은 타입이 다르면 오류가 발생한다.
age: number;
}
const person: Person = { // merge
name: "kim",
age: 27,
};
클래스
제너릭
- 함수, 인터페이스, 클래스 등을 다양한 타입과 함께 사용할 수 있게 해주는 타입스크립트 문법
제너릭 함수
: 함수에 인수에 따라 원하는 반환 값 타입을 정해서 사용할 수 있다.
* 함수 명 뒤 <T> 선언, 매개 변수 반환 타입 T 를 작성
// 제너릭
function func1(value: unknown) {
return value;
}
let num1 = func1(10);
// num1.toFixed(); // error - unknown 연산 불가
if (typeof num1 === "number") {
num1.toFixed();
}
let str1 = func1("string");
// str.toUpperCase(); // error - unknown 연산 불가
// 제너릭 함수
function func2<T>(value: T): T {
return value;
}
let num2 = func2(10);
num2.toFixed();
let str2 = func2("string");
str2.toUpperCase();
let arr = func2<[number, number, number]>([1, 2, 3]);
제너릭 함수 활용
// 1 : 2개의 타입을 사용하는 경우
function swap<T, U>(a: T, b: U) {
return [b, a];
}
const [a, b] = swap("1", 2);
// 2 : 다양한 배열 타입을 인수로 받는 경우
function returnFirstValue1<T>(data: T[]) {
return data[0];
}
let num = returnFirstValue1([0, 1, 2]); // number
let str = returnFirstValue1([1, "hello", "mynameis"]); // number | string
// 3 : 첫번째 요소만 타입을 사용하고, 나머지는 상관 없는 경우
function returnFirstValue2<T>(data: [T, ...unknown[]]) {
return data[0];
}
let str2 = returnFirstValue2([1, "hello", "mynameis"]); // number
// 4 : 타입 변수 제한하는 경우
function getLength<T extends { length: number }>(data: T) {
return data.length;
}
getLength("123");
getLength([1, 2, 3]);
getLength({ length: 1 });
// getLength(undefined); // error - T가 length를 가지고 있지 않아서
// getLength(null); // error - T가 length를 가지고 있지 않아서
map, forEach 타입 함수 작성해보기
- map, forEach 함수를 제너릭 문법을 사용하여 직접 작성
- vscode에서 map, forEach 함수에 Alt 또는 Ctrl 클릭 후 마우스를 가져다 대면 타입스크립트에서 정의한 제너릭을 볼 수 있다.
// map
const arr = [1, 2, 3];
const newArr = arr.map((it) => it * 2);
function map<T, U>(arr: T[], callback: (item: T) => U): U[] {
let result = [];
for (let i = 0; i < arr.length; i++) {
result.push(callback(arr[i]));
}
return result;
}
map(arr, (it) => it.toString());
// forEach
const arr2 = [1, 2, 3];
const newArr2 = arr2.forEach((it) => console.log(it));
function forEach<T>(arr: T[], callback: (item: T) => void) {
for (let i = 0; i < arr.length; i++) {
callback(arr[i]);
}
}
forEach(arr2, (it) => it.toFixed());
forEach(['a', 'b', 'c'], (it) => it.toUpperCase());
제너릭 인터페이스, 제너릭 별칭
- 제너릭은 인터페이스에서 적용이 가능하다.
- 인덱스 시그니터와 같이 사용하면, 더 유연한 타입 지정이 가능하다.
- 타입 별칭에서 제너릭 문법을 사용할 수 있다.
// 제너릭 인터페이스
interface KeyPair<K, V> {
key: K;
value: V;
}
let keyPair: KeyPair<string, number> = {
key: "key",
value: 0,
};
let keyPair2: KeyPair<boolean, string[]> = {
key: true,
value: ["1"],
};
// 인덱스 시그니처와 같이 사용하기
interface Map<V> {
[key: string]: V;
}
let stringMap: Map<string> = {
key: "value",
};
let booleanMap: Map<boolean> = {
key: true,
};
// 타입 별칭으로 제너릭 지정
type Map2<V> = {
[key: string]: V;
};
let stringMap2: Map2<string> = {
key: "string",
};
// 활용
interface Developer {
type: "developer";
skill: string;
}
// interface User {
// name: string;
// profile: Student | Developer;
// }
interface User<T> {
name: string;
profile: T;
}
function func(user: User<Developer>) {
console.log(`${user.profile.type} study`);
}
// const developerUser: User = {
// name: "kim",
// profile: {
// type: "developer",
// skill: "typescript",
// },
// };
const developerUser: User<Developer> = {
name: "이정환",
profile: {
type: "developer",
skill: "TypeScript",
},
};
제너릭 클래스
- 클래스의 이름 뒤에 타입 변수를 선언하면 제네릭 클래스
- 생성자에 인수로 전달하는 값이 있을 경우 타입 변수에 할당할 타입을 생략 가능
// 제너릭 클래스
// class NumberList {
// constructor(private list: number[]) { }
// push(data: number) {
// this.list.push(data);
// }
// pop() {
// return this.list.pop();
// }
// print() {
// console.log(this.list);
// }
// }
// const numberList = new NumberList([1, 2, 3]);
class List<T> {
constructor(private list: T[]) { }
push(data: T) {
this.list.push(data);
}
pop() {
return this.list.pop();
}
print() {
console.log(this.list);
}
}
const numberList = new List([1, 2, 3]); // new List<number>([1, 2, 3]); 동일한 코드
const stringList = new List(["1", "2"]); // new List<string>(["1", "2"]);
프로미스(Promise) 제너릭
- promise는 제너릭 클래스로 구현되어 있어서, 변수에 할당한 타입으로 resolve 타입이 결정된다.
- 그러나, reject 인수에 전달하는 값(실패 값)타입은 정의할 수 없고 자동으로 추론하지 못하고 unknown으로 고정된다.
// Promise
// 1. 기본 타입
const promise = new Promise<number>((resolve, reject) => {
setTimeout(() => {
// 결과값 : 20
resolve(20);
}, 3000);
});
promise.then((response) => {
// response는 number 타입
console.log(response);
});
promise.catch((error) => {
if (typeof error === "string") {
console.log(error);
}
});
// 2. 객체 변수
interface Post {
id: number;
title: string;
content: string;
}
function fetchPost(): Promise<Post> {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({
id: 1,
title: "게시글 제목",
content: "게시글 본문",
});
}, 3000);
});
}
const PostRequest = fetchPost();
PostRequest.then((response) => {
console.log(response.id);
});
promise.catch((error) => {
if (typeof error === "string") {
console.log(error);
}
});
출처
- 한 입 크기로 잘라먹는 타입스크립트(TypeScript)
'Frontend > TypeScript' 카테고리의 다른 글
[TypeScript] TypeScript 유틸리티 타입 - 6 (0) | 2024.04.19 |
---|---|
[TypeScript] TypeScript 타입 조작 기능 - 5 (0) | 2024.04.17 |
[TypeScript] TypeScript 함수 타입 이해 - 3 (0) | 2024.04.14 |
[TypeScript] TypeScript 타입 시스템 이해 - 2 (0) | 2024.04.14 |
[TypeScript] TypeScript 기본 문법 - 1 (0) | 2024.04.14 |