노트

타입 추론과 타입 검사

Type Inference and Type Checking

프런트엔드#ts · 연결된 개념 6개

쉽게 말하면

타입 추론은 컴파일러가 처음 들어온 값을 보고 '여긴 숫자 자리'라고 정하는 단계이고, 타입 검사는 그 뒤로 정해진 자리에 맞는 값만 오는지 확인하는 단계예요. 표기를 안 써도 안전한 이유죠.

비유가 깨지는 곳 자리가 꼭 값만 보고 정해지진 않아요. click 이벤트 콜백의 e처럼 위치가 타입을 알려 주기도 해요. ': 타입' 표기는 추론을 덮어써서 구체적 정보가 사라지니, 그럴 땐 satisfies를 쓰기도 해요.

타입 추론(Type Inference)은 표기가 없어도 컴파일러가 값의 타입을 정하는 단계이고, 타입 검사(Type Checking)는 정해진(추론됐거나 명시된) 타입을 코드가 지키는지 확인하는 단계다. 보통 추론이 먼저 일어나고, 그 결과를 기준으로 검사한다.

let count = 10       // 추론: number
count = 'hello'      // 검사: string은 number에 넣을 수 없음 ❌

추론이 일어나는 곳

  • 변수 초기값, 함수 반환값, 구조 분해
  • 문맥적 타이핑(Contextual Typing): 위치가 타입을 알려 준다. addEventListener('click', e => …)의 e는 'click' 덕분에 MouseEvent가 된다
  • const status = 'success'는 리터럴 타입(Literal Type) 'success', let status = 'success'는 string으로 넓게 추론된다. 바뀔 수 있는지가 기준이다

검사가 보는 것

  • 필요한 속성이 다 있는가(구조 비교, 구조적 타이핑)
  • 객체 리터럴에 없는 속성을 더 넣지 않았나(초과 속성 검사, Excess Property Checking)
  • 함수 인자가 매개변수 타입에 맞는가

추론이 너무 넓게(any) 잡히거나 의도와 다르면 표기를 달아 보정한다. 그런데 : Type 표기는 추론 결과를 덮어써서 구체적인 정보가 사라진다. 검사는 받되 추론은 유지하고 싶을 때 쓰는 것이 satisfies다. 추론을 포기하는 any는 피한다. 추론된 결과를 다시 좁히는 방법은 타입 좁히기와 타입 가드이다.

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 기본형 집착

    전화번호·금액·우선순위 같은 도메인 개념을 끝까지 문자열이나 숫자로만 다루는 냄새. 같은 검증과 포맷 코드가 여기저기 반복되고, 문자열로 모든 걸 표현하는 "stringly typed" 코드가 된다.

  • 매핑된 타입과 keyof

    매핑된 타입(Mapped Types)은 기존 타입의 키를 하나씩 돌며 새 타입을 만드는 문법([K in keyof T]: …)이다. keyof T는 객체 타입의 키 유니언을, T[K](인덱스 접근 타입, Indexed Access Type)는 그 키의 값 타입을 꺼낸다.

  • type과 interface

    type(타입 별칭, Type Alias)과 interface는 둘 다 타입에 이름을 붙이는 방법이다. 객체 모양을 정의할 때는 대부분 바꿔 써도 되지만, 확장 방식과 표현 범위가 다르다.

  • 제네릭

    제네릭(Generics)은 타입을 매개변수처럼 받아, 여러 타입에 같은 로직을 재사용하면서도 타입 정보를 잃지 않게 하는 기능이다.

  • 조건부 타입과 infer

    조건부 타입(Conditional Types)은 T extends U ? X : Y 꼴로, 타입 수준에서 if-else를 하는 문법이다. infer는 조건부 타입 안에서 타입의 일부를 변수로 붙잡아 꺼낼 때 쓴다.

보기 옵션