미래 지향적인 웹 앱 구축: The Codest의 전문가 팀이 제공하는 인사이트
The Codest가 최첨단 기술로 확장 가능한 대화형 웹 애플리케이션을 제작하고 모든 플랫폼에서 원활한 사용자 경험을 제공하는 데 탁월한 성능을 발휘하는 방법을 알아보세요. Adobe의 전문성이 어떻게 디지털 혁신과 비즈니스를 촉진하는지 알아보세요...
제네릭은 단일 유형이 아닌 여러 유형에서 작동하는 재사용 가능한 코드 조각을 제공합니다. 제네릭은 함수 매개변수와 유사하게 유형을 변수로 취급하고 사용 시 이를 지정하는 방법을 제공합니다.
제네릭은 함수(제네릭 함수 생성), 클래스(제네릭 클래스 생성) 및 인터페이스(제네릭 인터페이스 생성)와 함께 사용할 수 있습니다.
제네릭의 가장 일반적인 용도는 배열을 선언하는 것인데, 이 사실을 모르고도 과거에 제네릭을 사용해 본 적이 있을 것입니다:
const myArray: 문자열[];
언뜻 보기에는 그리 특별하지 않습니다. myArray
를 문자열 배열로 사용할 수 있지만 일반 선언과 동일합니다:
const myArray: 배열;
아주 간단한 예제부터 시작하겠습니다. 이 바닐라 JS 함수를 TypeScript로 어떻게 이식할 수 있을까요?
함수 getPrefiledArray(filler, length) {
반환 (새로운 배열(길이)).채우기(필러);
}
이 함수는 주어진 양으로 채워진 배열을 반환합니다. 필러
따라서 길이
는 숫자
를 반환하고 전체 함수는 필러
- 하지만 필러란 무엇인가요? 이 시점에서 필러는 무엇이든 될 수 있으므로 한 가지 옵션은 다음을 사용하는 것입니다. any
:
함수 getPrefiledArray(filler: any, length: number): any[] {
반환 (새로운 배열(길이)).채우기(필러);
}
사용 any
는 확실히 일반적입니다 - 말 그대로 무엇이든 전달할 수 있으므로 정의에서 "단일 유형이 아닌 여러 유형으로 작업"은 완전히 다루지만 필러
유형과 반환 유형을 지정할 수 있습니다. 이 경우 어떤 공통된 것을 반환하고 싶고, 이 공통된 것을 명시적으로 다음과 같이 정의할 수 있습니다. 유형 매개변수:
함수 getPrefiledArray(필러: T, 길이: 숫자): T[] {
반환 (새로운 배열(길이)).채우기(필러);
}
를 클릭하고 이렇게 사용하세요:
const prefilledArray = getPrefiledArray(0, 10);
좀 더 일반적인 다른 경우를 살펴보겠습니다. 실제로 함수에 타입을 사용하는 이유는 무엇일까요? 저에게는 함수에 전달되는 인수가 상호작용하고자 하는 일부 속성을 갖도록 하기 위해서입니다.
다시 한 번 간단한 바닐라 JS 함수를 TS로 포팅해 보겠습니다.
함수 getLength(thing) {
return thing.length;
}
사소하지 않은 수수께끼가 하나 있습니다. 길이
속성으로 설정하는 것이 가장 먼저 떠오를 수 있습니다:
함수 getLength(thing: typeof Array):number {
return thing.length;
}
는 문맥에 따라 맞을 수도 있고, 전반적으로 약간 일반적입니다. 여러 유형의 배열에서 작동하지만, 사물이 항상 배열이어야 하는지, 축구장인지 바나나 껍질인지 알 수 없는 경우에는 어떻게 해야 할까요? 이 경우 사물의 공통 속성을 객체의 속성을 정의할 수 있는 구조체, 즉 인터페이스로 수집해야 합니다:
인터페이스 IThingWithLength {
길이: 숫자
}
다음을 사용할 수 있습니다. IThingWithLength
인터페이스의 유형으로 thing
매개변수입니다:
함수 getLength(thing: IThingWithLength):number {
return thing.length;
}
이 간단한 예제에서는 솔직히 말해서 완벽하게 괜찮을 것이지만, 이 유형을 일반적으로 유지하고 첫 번째 예제에서 발생한 문제에 직면하지 않으려면 일반 제약 조건:
함수 getLength(thing: T):number {
return thing.length;
}
를 클릭하고 사용하세요:
인터페이스 IBananaPeel {
두께: 숫자
길이: 숫자
}
const bananaPeel: IBananaPeel = {두께: 0.2, 길이: 3.14};
getLength(바나나껍질);
사용 확장
은 다음을 보장합니다. T
에 정의된 속성을 포함하게 됩니다. IThingWithLength
.
지금까지는 제네릭 함수로 작업했지만, 제네릭이 빛을 발하는 곳은 여기뿐만이 아니니 클래스에 어떻게 접목할 수 있는지 살펴봅시다.
먼저 바나나 바구니에 바나나 다발을 보관해 보겠습니다:
바나나 클래스 {
생성자(
public length: 숫자
public color: 문자열
public ionizingRadiation: 숫자
) {}
}
class BananaBasket {
private bananas: Banana[] = [];
add(banana: 바나나): void {
this.bananas.push(banana);
}
}
const bananaBasket = new BananaBasket();
bananaBasket.add(new Banana(3.14, 'red', 10e-7));
이제 같은 유형의 다른 물건에 대한 범용 바구니를 만들어 보겠습니다:
클래스 Basket {
사적인 것들: T[] = [];
add(thing: T): void {
this.stuff.push(thing);
}
}
const bananaBasket = new Basket();
마지막으로, 바구니가 방사성 물질 용기이고 다음과 같은 물질만 보관할 수 있다고 가정해 보겠습니다. 이온화방사선
속성입니다:
인터페이스 IRadioactive {
이온화 방사: 숫자;
}
RadioactiveContainer 클래스 {
비공개입니다: T[] = [];
add(thing: T): void {
this.stuff.push(thing);
}
}
마지막으로 일반 인터페이스를 사용하여 모든 지식을 모아 방사능 제국을 건설해 보겠습니다:
// 컨테이너에 대한 공통 속성 정의
인터페이스 IRadioactive {
이온화 방사: 숫자;
}
// 방사성 물질을 정의합니다.
인터페이스 IBanana extends IRadioactive {
길이: 숫자;
color: 문자열
}
// 방사능이 아닌 것을 정의합니다.
인터페이스 IDog {
weight: 숫자
}
// 방사성 물질만 담을 수 있는 컨테이너의 인터페이스를 정의합니다.
인터페이스 IRadioactiveContainer {
add(thing: T): void;
getRadioactivity():number;
}
// 방사성 컨테이너 인터페이스를 구현하는 클래스를 정의합니다.
class RadioactiveContainer 구현 IRadioactiveContainer {
비공개 물건: T[] = [];
add(thing: T): void {
this.stuff.push(thing);
}
getRadioactivity(): number {}
return this.stuff.reduce((a, b) => a + b.ionizingRadiation, 0)
}
}
// 오류! 'IDog' 유형이 'IRadioactive' 제약 조건을 만족하지 않습니다.
// 그리고 방사능 컨테이너 안에 개를 보관하는 것은 좀 잔인합니다.
const dogsContainer = 새로운 방사성 컨테이너();
// 모두 좋은 가족!
const radioactiveContainer = new RadioactiveContainer();
// 방사성 폐기물을 분류하는 것을 잊지 마세요 - 바나나만을 위한 별도의 빈을 만드세요.
const bananasContainer = new RadioactiveContainer();
여기까지입니다!