Gwangju-Web-Study / WoowahanTS_Study

✏️우아한 타입스크립트 with 리액트 스터디
6 stars 2 forks source link

3.3.4 제한된 제네릭을 사용하는 경우와 예시를 들어 설명해주세요. #14

Closed BaekWeb closed 2 months ago

BaekWeb commented 2 months ago

📝 p112~p113

❓ 제한된 제네릭은 타입 제약 조건을 설정하여 타입을 제약하는 것을 말한다. 이때 제한된 제네릭을 사용하는 경우와 예시를 들어 설명해주세요. 단, 책의 예시는 제외합니다

fe-Jay commented 2 months ago

키 제한

type Book = {
  title: string;
  author: string;
  pages: number;
};

const myBook: Book = {
  title: "우아한 타입스크립트 with 리액트",
  author: "우아한형제들",
  pages: 380
};

// 1. getBookProperty 함수 선언
// 1-1. K타입을 T타입 객체의 키 중 하나로 타입 제한
// 1-2. T 타입의 객체와 K 타입의 키를 인자로 받음
function getBookProperty<K extends keyof Book>(book: Book, key: K): Book[K] {
  return book[key];
}

// 2. 사용 예시
console.log(getBookProperty(myBook, "title")); // "우아한 타입스크립트 with 리액트"
console.log(getBookProperty(myBook, "author")); // "우아한형제들"
console.log(getBookProperty(myBook, "pages")); // 380

console.log(getBookProperty(myBook, "isbn")); 
// 오류: 'isbn'은 'Book' 타입의 프로퍼티가 아닙니다

// 4. 타입 안전성 예시
const title: string = getBookProperty(myBook, "title"); // OK
const pages: number = getBookProperty(myBook, "pages"); // OK

const wrongType: number = getBookProperty(myBook, "title");
// 오류: string 타입을 number 타입에 할당할 수 없습니다
hyeonseong2023 commented 2 months ago

매개변수 타입 일치

function plus<T extends string | number>(arg1: T, arg2: T): T {
  return (arg1 as any) + (arg2 as any);
}

plus(1, 2); // 유효
plus("a", "b"); // 유효
plus(1, "b"); // 컴파일 에러
gwangminjun commented 2 months ago

예시

interface Minjun {
    name: string;
    pair: string;
}

// pair가 string 또는 null일 수 있으므로 반환 타입을 string | null로 설정
function getPair<T extends Minjun>(obj: T): string {
    return obj.pair;
}}

// 올바른 상황
const LoveMinjun = { name: '양민준', pair: '박규영' };
console.log(getPair(LoveMinjun)); // 출력: 박규영

// 현재 상황
const CurrentMinjun = { name: '양민준', pair: null };

// 오류 발생 : NULL
BaekWeb commented 2 months ago

제네릭 타입 제한

extends 를 활용한 타입 제한

// 일반적인 제네릭 함수
function logLength<T>(text: T): T {
    // string 메서드 사용
    console.log(text.length); // ==> 에러! string이 안올수도있음!
    return text;
}

정의된 타입 이용 제네릭 (extends 활용)

interface LengthType {
    // 제한할 속성 (length는 무조건 있어야해!)
    length: number;
}

// 확장된 제네릭 함수
function LogLength<T extends LengthType>(text: T): T{
    text.length;
    return text;
}
// => length 속성이 있는 것들만 받을 수 있다.

LogTextLength('a'); // OK
LogTextLength({ length: 10 }); // OK (length가 있긴하니까)
// LogTextLength(10); ==> 에러! 숫자엔 length 속성 없음

확장된 제네릭 함수의 T는 LengthType을 확장하여 해당 인터페이스의 하위이니까 LengthType의 속성(length)을 가지는 것들을 입력받는다는 뜻

keyof 를 활용한 타입 제한

interface Uesr {
  name: string;
  age: number;
}

// User 인터페이스의 key값(name,age)를 확장
function UserOption<T extends keyof User>(item: T): T {
  return item;
}

// User 인터페이스의 key값만 받을 수 있다
UserOption('name'); // name
UserOption('age'); // age
UserOption('job'); // ==> 에러!

console.log(typeof UserOption('name')); // string

keyof 를 활용하면 keyof 다음에 오는 인터페이스가 가진 key들만 입력받을 수 있다.

https://taylog.tistory.com/209