전체 글

개발자 린다씨
👶 TypeScript

한정된 다형성으로 인수의 개수 정의하기

한정된 다형성으로 인수의 개수 정의하기 가변 인수 함수 (= 임의의 개수의 인수를 받는 함수)에서도 한정된 다형성을 사용할 수 있습니다. 예를 들어 JavaScript의 내장 call 함수를 직접 구현하면, 아래처럼 정의하고 사용할 수 있습니다. call은 함수 하나와 임의 개수의 인수를 받아서 이 인수들을 함수에 건네 호출하는 함수입니다. function call( f: (...args: unknown[]) => unknown, ...args: unknown[] ): unknown { return f(...args) } function fill(length: number, value: string): string[] { return Array.from({length}, () => value) } cal..

👶 TypeScript

여러 제한을 적용한 한정된 다형성

여러 제한을 적용한 한정된 다형성 type TreeNode = { value: string } type LeafNode = TreeNode & { isLeaf: true } type InnerNode = TreeNode & { children: [TreeNode] | [TreeNode, TreeNode] } let a: TreeNode = {value: 'a'} let b: LeafNode = {value: 'b', isLeaf: true} let c: InnerNode = {value: 'c', children: [b]} function mapNode( // ① node: T, // ② f: (value: string) => string ): T{ // ③ return { ...node, value: ..

👶 TypeScript

한정된 다형성

한정된 다형성 이번엔 이진트리 예제를 사용합니다. 기본적으로 이진트리의 특징은 아래와 같습니다. 이진트리는 자료구조입니다. 이진트리는 노드를 갖습니다. 노드의 값을 가지며 최대 두 개의 자식 노드를 가리킬 수 있습니다. 노드는 잎 노드(leaf node: 자식이 없음) 또는 내부 노드(inner node: 적어도 한 개의 자식을 가짐) 둘 중 하나의 타입을 갖습니다. "T는 제네릭 타입이며, 이것은 T와 같은 타입이어야 한다"는 말로 표현할 수 없는 상황이 많습니다. 때론 U 타입은 적어도 T 타입을 포함하는 기능이 필요합니다. 이러한 상황을 U가 T의 상한 한계(upper bound)라고 설명합니다. 아래와 같은 세 종류의 노드를 갖는 이진트리를 구현한다고 해보겠습니다. 일반 TreeNode 자식을 갖..

👶 TypeScript

제네릭 타입 별칭

제네릭 타입 별칭 간단한 예를 통해 타입 별칭에서 제네릭을 활용해 보겠습니다. click이나 mousedown 같은 DOM 이벤트를 설명하는 FirstEvent 타입을 정의해 보겠습니다. type FirstEvent = { target: T type: string } 타입 별칭에선 타입 별칭명과 할당 기호(=) 사이에만 제네릭 타입을 선언할 수 있습니다. FirstEvent의 target 프로퍼티는 , 등 이벤트가 발생한 요소를 가리킵니다. 예시로 버튼 이벤트는 아래처럼 표현할 수 있습니다. type FirstEvent = { target: T type: string } type ButtonEvent = FirstEvent FirstEvent 같은 제네릭 타입을 사용할 때는 타입이 자동적으로 추론되지 않..

👶 TypeScript

제네릭 타입 추론

제네릭 타입 추론 대부분의 상황에서 TypeScript는 제네릭 타입을 잘 추론해 냅니다. function map(array: T[], f: (item: T) => U): U[] { let result = [] for (let i = 0; i _ === 'a' // U 타입을 반환하는 함수 ) 위의 코드 map 함수를 함수 아래처럼 호출하면 TypeScript는 T를 string으로, U를 boolean으로 추론합니다. 그러나 제네릭도 명시적으로 지정할 수 있습니다. 제네릭 타입을 명시할 땐 모든 필요한 제네릭 타입을 명시하..

👶 TypeScript

제네릭을 어디에 선언할 수 있을까?

제네릭을 어디에 선언할 수 있을까? TypeScript에선 호출 시그니처를 정의하는 방법에 따라 제네릭을 추가하는 방법이 정해져 있습니다. type Filter = {(array: T[], f: (item: T) => boolean) =>T[]} // ① let filter: Filter = //... type Filter = { // ② (array: T[], f: (item:T) => boolean): T[] } let filter: Filter = // ... type Filter = (array: T[], f: (item: T) => boolean) => T[] // ③ let filter: Filter = // ... type Filter = (array: T[], f: (item: T) => ..

👶 TypeScript

언제 제네릭 타입이 한정되는가?

언제 제네릭 타입이 한정되는가? 제네릭 타입의 선언 위치에 따라 타입의 범위뿐 아니라 TypeScript가 제네릭 타입을 언제 구체 타입으로 한정하는지도 결정됩니다. type Filter = (array: T[], f: (item: T) => boolean) => T[] let filter: Filter = (array, f) => { const result = [] for(let i = 0; i < array.length; i++){ const item = array[i] if(f(item)) { result.push(item) } } return result } 위의 예시에서 를 호출 시그니처의 일부로 선언했으므로 TypeScript는 Filter 타입의 함수를 실제 호출할 때 구체 타입을 T로 한정..

👶 TypeScript

다형성

다형성 모든 타입은 구체 타입(concrete type)입니다. boolean string Date[] {a: number} | {b: string} (numbers: number[]) => number 기대하는 타입을 정확하게 알고 있고, 실제 이 타입이 전달되었는지 확인할 때는 구체 타입이 유용합니다. 하지만 때론 어떤 타입을 사용할지 미리 알 수 없는 상황이 있는데, 이런 상황에선 함수를 특정 타입으로 제한하기 어렵습니다. JavaScript로 filter를 이용하여 배열을 반복하면서 정제하는 코드를 아래처럼 구현할 수 있습니다. function filter(array, f){ let result = [] for(let i = 0; i < array.length; i++) { let item = a..

👶 TypeScript

오버로드된 함수 타입

오버로드된 함수 타입 호출 시그니처에서 사용한 함수 타입 문법(type Fn = (...) => ...)은 단축형 호출 시그니처(shorthand call signature)입니다. 해당 호출 시그니처를 더욱 명확하게 표현할 수 있습니다. 다시 Log를 예로 살펴보겠습니다. // 단축형 호출 시그니처 type Log1 = (message: string, userName?: string) => void // 전체 호출 시그니처 type Log2 = { (message: string, userName?: string): void } 위의 두 코드는 문법만 조금 다를 뿐 모든 면에서 같습니다. 위의 Log 함수처럼 간단한 상황이라면 단축형을 활용하되 더 복잡한 함수라면 전체 시그니처를 사용하는 것이 좋을 때도..

개발자 린다씨
Cozy_Linda