JS, 내 안에 타입있다 2 : TypeScript 심화개념🗼

밍갱·2025년 3월 7일

1. 타입 어노테이션 Type annotation과 타입 추론🕵

01. 타입 명시 Type annotation이란?

annotation 은 "주석"이라는 뜻으로, TypeScript에서 변수나 함수 등에 데이터 타입을 지정하기 위해 주석을 다는 것을 타입 명시 type annotation이라고 한다. 즉, 어떤 값이 어떤 타입을 참조하고 있는지 개발자가 직접 타입을 명시하여 TypeScript에게 알려주는 것이다. 한번 타입을 명시하면 해당 타입만 사용할 수 있으며, 다른 타입 사용시 TypeScript 컴파일러가 에러를 던진다.

  • 사용법
//변수
let name: string = 'Owen';
let age: number = 30;
let isMarried: boolean = false;

//배열
let animals: string[] = ['cat', 'dog', 'cow'];

//객체 리터럴
let point: {x: number, y: number} = {
	x: 10,
	y: 20
}

//함수
const logNumber: (i: number) => void = (i: number) => {
	console.log(i);
}

//null과 undefined
let haveNothing: null = null;
let nothing: undefined = undefined;

02. 타입 추론이란?

개발자가 타입을 명시적으로 지정하지 않아도, TypeScript 컴파일러가 코드 문맥을 통해 타입을 자동으로 추론해주는 것을 타입 추론이라고 한다. 타입 추론은 TypeScirpt의 중요한 기능 중 하나로, 타입 안정성을 유지할 수 있게 한다. 또한, 여러 타입을 동시에 사용할 경우 최적 공통 타입을 알아서 계산해준다.

  • 기본 타입 추론
//변수 타입 추론
let num = 10; // number로 추론
let str = "Hello"; // string으로 추론
let bool = true; // boolean으로 추론

//배열 타입 추론
let numbers = [1, 2, 3, 4, 5]; // number[]로 추론
let strings = ["a", "b", "c"]; // string[]로 추론

//객체 리터럴 타입 추론
let person = {
    name: "Alice",
    age: 25
}; // { name: string; age: number }로 추론

person.name = "Bob"; // 정상
person.age = 30; // 정상
person.age = "thirty"; // 오류: 'string' 형식은 'number' 형식에 할당할 수 없습니다.

//함수 return값 타입 추론
function add(a: number, b: number) {
    return a + b; // number로 추론
}

const result = add(5, 3); // result는 number로 추론
  • 컨텍스트를 통한 타입 추론
//함수의 매개변수를 통한 return값 타입 추론
let add = (a: number, b: number) => a + b; // (a: number, b: number) => number로 추론

//콜백함수의 타입 추론
let numbers = [1, 2, 3, 4, 5];
numbers.forEach(num => {
    console.log(num); // num은 number로 추론
});

03. Type annotation이 필요한 경우

타입 추론에 의존하게 되면 TypeScript를 쓰는 이유인 "안전한 코드 작성"과 멀어질 수 있는 위험이 있다. 그래서 처음 TypeScript를 접했거나 익숙치 않은 상황이라면 타입 어노테이션을 꼼꼼히 해주는 습관이 필요하다.
또한, 타입 추론이 되지 않은 경우도 발생할 수 있다. 그럴 때는 꼭 타입 어노테이션을 작성해주어야 한다.

  • 함수가 any타입을 return하고, 이 값을 명확하게 해야하는 경우
  • 어떤 변수를 선언한 이후에 다른 라인에서 초기화 하는 경우
  • 변수가 추론할 수 없는 타입(대입될 값이 일정하지 않거나 여러 타입이 지정)을 가지는 경우

2. 제네릭 Generics

01. 제네릭 Generics이란?

기본 타입은 항상 고정되어 변하지 않는다. 여기에 약간의 유연성을 더한 유니온 타입이 있지만, 이마저도 프로그래밍 환경에서 발생하는 모든 변수를 대처할 수 없다. 그래서 타입을 고정된 값으로 명시하지 않고, 변수 를 통해 유연하게 코딩할 수 있도록 하는 것이 바로 제네릭 Generics이다. 즉, 타입을 변수화하여 마치 클래스나 함수 등에서 파라미터처럼 사용하는 것을 뜻한다.

02. 제네릭 사용방법 : 기본 문법 < T >

기본적인 문법은 <> 안에 제네릭으로 받을 타입의 이름을 넣어주면 된다. 대표적으로 T, U 등을 많이 사용한다.

//일반 함수
function toArray<T>(a: T, b: T): T[] {
   return [a, b];
}

//화살표 함수
const toArray2 = <T>(a: T, b: T): T[] => { ... }

toArray<number>(1, 2); // 숫자형 배열
toArray<string>('1', '2'); // 문자형 배열
toArray<string | number>(1, '2'); // 혼합 배열

//TypeScript 타입 추론 기능으로 인해 제네릭을 안써줘도 타입 추론이 가능하다.
toArray(1, 2);
toArray('1', '2');
// 하지만 가끔 자동 타입 추론이 잘안되는 경우가 있기 때문에 직접 제네릭을 선언해야한다.
toArray<string | number>(1, '2');

03. 제네릭 사용방법 : 제네릭 함수

제네릭 함수를 활용하면 여러 타입을 처리할 수 있다.

function printAnything<T>(arr: T[]): void {
    for (let i = 0; i < arr.length; i++) {
        console.log(arr[i]);
    }
}

printAnything(['a', 'b', 'c']); // <string>을 써주지 않아도 타입 추론이 가능
printAnything([1, 2, 3]); // <number>를 써주지 않아도 타입 추론이 가능

3. 유틸리티 타입 Utility type

01. 유틸리티 타입 Utility type 이란?

유틸리티 타입이란 타입 변환을 용이하게 하기 위한 문법으로, 타입을 통해 간단한 계산을 수행해주는 타입이다. 유틸리티 타입을 쓰면 훨씬 더 간결한 문법으로 타입을 정의할 수 있으며, 특히 이미 정의해 놓은 타입을 변환할 때 유용하다.

02. 유틸리티 타입 종류

타입명설명
Pick<T, K>T에서 프로퍼티 K의 집합을 선택해 타입을 구성
Omit<T, K>T의 모든 프로퍼티에서 K를 제거한 타입을 구성
Exclude<T, U>T에서 U에 할당할 수 있는 모든 속성을 제외한 타입을 구성
Partial< T >T의 모든 프로퍼티를 선택적으로 만드는 타입을 구성
ReadOnly< T >T의 모든 프로퍼티를 읽기 전용(재할당 X)으로 설정한 타입을 구성
Record<K, T>타입 T의 프로퍼티의 집합 K로 타입을 구성
주로 타입의 프로퍼티들을 다른 타입에 매핑 시키는 데 사용
Extract<T, U>T에서 U에 할당 할 수 있는 모든 속성을 추출하여 타입을 구성
ReturnType< T >T 함수 타입의 반환 타입을 구성, 함수의 반환 타입을 추론하는 데 유용
Parameters< T >T 함수 타입의 매개변수 타입을 튜플로 구성
Awaited< T >Promise의 결과 타입을 추론
비동기 함수의 반환 타입을 처리하거나 Promise로 감싸진 값을 추출할 때 유용

타입 어노테이션 TypeScript 공식 문서
타입 어노테이션/타입 추론 참고 사이트
제네릭 참고 사이트
유틸리티 타입 참고 사이트

profile
미술 전공에서 프론트엔드 개발까지

0개의 댓글