본문 바로가기
개발 일지/TIL

[ TypeScript ] 제네릭 & 타입 추론

by CODESIGN 2023. 1. 17.

제네릭


제네릭이란 타입을 마치 함수의 파라미터처럼 사용하는 것

 

아래 코드는 text라는 파라미터를 받아 그대로 text를 반환한다. 

아래의 코드에서는 string이 들어와도 타입은 any로 반환하고 숫자가 들어와도 any를 반환한다.

반환을 할 때 그에 맞는 타입을 반환하고 싶을 때 제네릭을 사용하면 된다. 

function getText(text: any): any {
  return text;
}

getText('hi'); // 'hi'
getText(10); // 10
getText(true); // true

 

<T>를 사용한 아래 코드가 제네릭의 기본 문법이다.

function getText<T>(text: T): T {
  return text;
}

getText<string>('hi');
getText<number>(10);
getText<boolean>(true);

 

 

추가 예시


// 배열의 특정 값을 반환한다
function getItemArray(arr: any[], index: number): any {
  return arr[index];
}

// 배열에 item을 추가한다
function pushItemArray(arr: any[], item: any): void {
  arr.push(item);
}

// string과 number 배열
const techStack = ['js', 'react'];
const nums = [1, 2, 3, 4];

getItemArray(techStack, 0); // 'js'
pushItemArray(techStack, 'ts'); // ['js', 'react', 'ts']

getItemArray(nums, 0); // 1
pushItemArray(nums, 5); // [1, 2, 3, 4, 5];

→ 위 코드를 제네릭으로 변경

function getItemArray<T>(arr: T[], index: number): T {
  return arr[index];
}

function pushItemArray<T>(arr: T[], item: T): void {
  arr.push(item);
}

const techStack = ['js', 'react'];
const nums = [1, 2, 3, 4];

getItemArray(techStack, 0); // 'js'
pushItemArray<string>(techStack, 'ts'); // ['js', 'react', 'ts']

// pushItemArray<number>(techStack, 123); // Error

getItemArray(nums, 0); // 1
pushItemArray(nums, 5); // [1, 2, 3, 4, 5];

 

 

제네릭 타입 변수


아래 코드는 에러가 난다. 그 이유는 input의 타입이 지정되지 않았는데 input의 길이를 구하려고 하기 때문이다. 

function printOut<T>(input: T): T {
  console.log(input.length); // Error: T doesn't have .length
  return input;
}

 

아래와 같이 고쳐주어 에러 해결이 가능하다.

[]를 추가해줌으로서 T에 배열을 받는다는 의미이다.

function printOut<T>(input: T[]): T[] {
  console.log(input.length);
  return input;
}

printOut([1, 2, 3]);

 

 

제네릭 제약 조건


function printOut<T>(input: T): T {
  console.log(input.length); // Error: T doesn't have .length
  return input;
}

위의 에러를 해결하기 위해 LengthWise interface로 확장을 해서 해결이 가능하다.

interface LengthWise {
  length: number;
}

function printOut<T extends LengthWise>(input: T): T {
  console.log(input.length);
  return input;
}

// printOut(10); // Error, 숫자 타입에는 `length`가 존재하지 않으므로 오류 발생
// printOut({ length: 0, value: 'hi' }); // `input.length` 코드는 객체의 속성 접근과 같이 동작하므로 오류 없음

 

 

타입 추론


타입을 적지 않아도 자동으로 타입을 추론해 준다.

 

기본 타입 추론


아래의 코드에서는 타입을 설정하지 않았다. 

 

let a = 123;
let b = 'abc';

a = 'abc';
b = 123;

const c1 = 123;
const c2 = 'abc';

const arr = [1, 2, 3];
const [n1, n2, n3] = arr;
arr.push('a'); // 경고 메시지가 뜬다. arr에는 num배열이기 때문이다

const obj = { numId: 1, stringId: '1' };
const { numId, stringId } = obj;
console.log(numId === stringId); // 자료형이 다른 두개는 비교가 될 수 없다는 경고가 뜬다.

 

 

함수 타입 추론


const func1 = (a = 'a', b = 1) => {
  return `${a} ${b};`;
};
func1(3, 6); // 경고: a는 string이기 때문에 숫자가 들어올 수 없다.

const v1: number = func1('a', 1);  func1은 string을 반환하기 때문에 number을 반환 할 수 없다.

const func2 = (value: number) => {
  if (value < 10) {
    return value;
  } else {
    return `${value} is big`;
  }
};

 

 

댓글