posts

typescript generic

Apr 23, 2026 updated Apr 23, 2026 genericstypescript

발표자 : 윤솔찬

발표 주제 : 제네릭

제네릭

Generic은 재사용을 목적으로 함수나 클래스의 선언 시점이 아닌,사용 시점에 타입을 선언할 수 있는 방법을 제공

와 같은 형식으로 사용하며 여기서 T는 타입 파라미터라고 불리우며 제네릭을 사용 할 때 외부에서 정의 할 수 있다

제네릭 사용 이유

재사용성이 높은 함수와 클래스를 생성할 수 있다.

여러 타입에서 동작이 가능하다. (한 번의 선언으로 다양한 타입에 재사용할 수 있다.)

코드의 가독성이 향상된다.

오류를 쉽게 포착할 수 있다.

any타입을 사용하면 컴파일 시 타입을 체크하지 않는다.

타입을 체크하지 않아 관련 메서드의 힌트를 사용할 수 없다.

컴파일 시에 컴파일러가 오류를 찾지 못한다.

generic도 any처럼 타입을 지정하지 않지만, 타입을 체크해 컴파일러가 오류를 찾을 수 있다.

받은 인수를 그대로 반환하는 함수

제네릭을 사용 하지 않았을 때

제네릭을 사용 했을 때

function add<T extends string|number>(x: T, y: T): T { return x + y; } add(1, 2); // 3 add(1, 2); // 이와 같이 타입지정을 따로 하지 않아도 인수의 타입을 보고 타입추론을 하여 타입이 들어간다 add('hello', 'world'); // 'helloworld'

파일 확장자에 따른 제네릭 사용 방법

const add = (x: T):T =>{ return x; } // .ts 확장자 파일에선 문제 없지만 .tsx 확장자 파일은 꺾쇠를 jsx로 인식하기에 다르게 해야한다 const add = <T extends {}>(x: T):T =>{ return x; } // 이와 같이 해당 다이아몬드 연산자가 jsx가 아니라는 걸 컴파일러에 알려준다

인터페이스

제네릭을 사용 하지 않았을 때

interface Mobile{ name: string; price: number; option: any; // any를 사용 하면 타입 에러를 잡아주지 못 한다 } const m1: Mobile = { name: 's21', price: 1000, option: { color: 'read', coupon: false }, }; const m2: Mobile = { name: 's20', price: 900, option: 'good', };

제네릭을 사용 했을 때

// 제네릭 인터페이스 interface Mobile { name: string; price: number; option: T; // 제네릭 타입 - option 속성에는 다양한 데이터 자료가 들어온다고 가정 } // 제네릭 자체에 객테 타입도 할당 할 수 있다. const m1: Mobile<{ color: string; coupon: boolean }> = { name: 's21', price: 1000, option: { color: 'read', coupon: false }, // 제네릭 타입의 의해서 option 속성이 유연하게 타입이 할당됨 }; const m2: Mobile = { name: 's20', price: 900, option: 'good', // 제네릭 타입의 의해서 option 속성이 유연하게 타입이 할당됨 };

제약 조건

제네릭에 extends 키워드를 이용하면 제네릭 타입으로 입력할 수 있는 타입의 종류를 제한할 수 있다.

제약 조건을 사용하지 않았을 땐 모든 타입이 허용된다

function identity(p1: T): T { return p1; } identity(1); identity('a'); identity(true); identity([]); identity({});

extends로 number와 string을 받아 T로 올 수 있는 타입을 number와 string으로 제한

type numOrStr = number | string; // 제네릭에 적용될 타입에 number | string 만 허용 function identity(p1: T): T { return p1; } identity(1); identity('a'); identity(true); // ERROR identity([]); // ERROR identity({}); // ERROR

조건부 타입

T extends U ? X : Y 의 형태로 T가 U에 할당 될 수 있다면 X 아니라면 Y가 된다는 걸 의미한다

// 제네릭이 string이면 문자열배열, 아니면 넘버배열 type 바꾸기 = T extends string ? string[] : number[]; type T1 = IsStringType; // type T1 = string[] type T2 = IsStringType; // type T2 = number[] const a: T1 = ['홍길동', '임꺾정', '박혁거세']; const b: T2 = [1000, 2000, 3000];

분산 조건부 타입

유니온 타입을 제네릭에 할당 하였을 때 유니온으로 묶인 타입 하나하나 조건부 타입 검사를 하고 결과값을

묶어 다시 유니온으로 반환

type IsStringType = T extends string ? 'yes' : 'no'; type T1 = IsStringType<string | string>; // 'yes'|'yes' // 1. (string | number) extends string ? 'yes' : 'no' // 2. string extends string ? 'yes' : 'no'| number extends string ? 'yes' : 'no'; // 3. 'yes'|'no'

분산 조건부 타입에서의 never

never 타입 여기도 좀 추가 상세하게

값을 포함할 수 없는 빈 타입

제네릭과 함수에서 허용되지 않는 매개변수

호환되지 않는 타입들의 교차 타입

빈 합집합(무의 합집합)

실행이 끝날 때 호출자에게 제어를 반환하지 않는 함수의 반환 타입

예) Node의process.exit

void는 호출자에게 함수가 유용한 것을 반환하지 않는다는 것이므로 혼동하지 않도록 한다.

절대로 도달할수 없을 esle 분기의 조건 타입

거부된 프로미스에서 처리된 값의 타입

never 타입으로 분산이 됐을 경우 이 타입은 제외 시킨다

type Never = T extends number ? T : never; type Types = number | string | object; type T2 = Never; // number // 1.(number extends number ? T : never) | (string extends number ? T : never) | (object extends number ? T : never) // 2. number | never | never // 3. number

타입이 유니온이나 제네릭일 때 함수 작성 주의점

function add<T extends string|number>(x: T, y: T): T { return x + y; // error TS2365: Operator '+' cannot be applied to types 'T' and 'T'. }

해당 함수는 정상적인 동작을 할 것 같지만 해당 T타입은 어떤 타입이던 반환 될 수 있기에 오류를 반환합니다

해당 오류를 해결 할 수 있는 방안은

function add(x: string, y: string): string; function add(x: number, y: number): number;

함수를 오버로딩한다

function add<T extends string | number>(x: T, y: T): string | number { if (typeof x === "string") { return x + y; } else { const x1 = x as number; const y1 = y as number; return x1 + y1; } }

인수의 타입을 체크하고 리턴을 해준다

해당 자료 :https://stackoverflow.com/questions/54470329/how-to-make-a-generic-add-operator-in-typescript-that-works-with-numbers-and-str

문제

배열의 길이를 반환하는 함수의 type를 지정하시오.

const studentNameList = ["bob", "json", "stefan"]; const GenericReturnFunc = (arg) => { return arg.length; } const a = GenericReturnFunc(studentNameList); console.log(a)

T에 height 라는 프로퍼티가 있는지 확실하지 않기에 나는 에러를 인터페이스와 제약조건을 활용해 타입을 지정하시오.

interface info { } const getHeight = (person:T):number => { return person.height // 에러 } const myInfo = { height: 171, }; console.log(getHeight(myInfo))