프로그래밍프론트엔드/백엔드 개발자

TypeScript의 Strict Function Types 옵션은 어떻게 작동하며, 함수의 공변성과 반공변성에 대한 타입 검사에 어떤 영향을 미치나요? 또한 어떤 경우에 서명 불일치가 컴파일 오류를 초래합니까?

Hintsage AI 어시스턴트로 면접 통과

답변.

질문의 역사

기본적으로 TypeScript는 함수의 타입 서명을 일치시키는 데 있어 일정 수준의 "느슨함"을 허용하고, 가역적 및 비가역적 함수가 호환된다고 판단합니다. TypeScript 2.6부터는 strictFunctionTypes 옵션이 도입되어 함수에 대한 엄격한 타입 검사를 보장하고, 특히 대규모 코드베이스에서 여러 종류의 오류를 예방합니다.

문제

엄격한 검사가 없으면 핸들러 함수나 콜백 함수가 더 많은 또는 더 구체적인 타입의 매개변수를 받는 상황이 발생할 수 있으며, 이는 개발자에게 눈치 채이지 않을 수 있습니다. 이로 인해 반환 타입의 공변성과 인자의 반공변성과 관련된 런타임 오류가 발생하게 됩니다.

해결책

strictFunctionTypes 옵션은 함수 매개변수 타입에 대해 엄격한 반공변성을 도입합니다. 이제 함수는 원본 타입의 매개변수가 대상 타입의 수퍼타입일 때만 호환됩니다. 반대의 경우는 허용되지 않습니다.

코드 예시:

type Animal = { name: string }; type Cat = { name: string; meow: () => void }; let animalHandler: (a: Animal) => void; let catHandler: (c: Cat) => void; animalHandler = catHandler; // strictFunctionTypes에서 오류: 인자가 너무 구체적임 catHandler = animalHandler; // 허용됨, Cat은 Animal의 하위 타입

주요 특징:

  • 함수의 인자는 "수퍼타입" 호환성(반공변성)을 검사받습니다.
  • 반환 값은 공변성(하위 타입 허용)에 대해 검사받습니다.
  • 서명 불일치는 컴파일 오류를 초래합니다.

함정이 있는 질문들.

엄격한 검사가 도입되기 전, 더 구체적인 매개변수를 가진 핸들러를 할당할 수 있었나요?

네, strictFunctionTypes가 활성화되기 전 TypeScript는 더 구체적인 함수를 일반 함수에 할당할 수 있도록 허용하였고, 이는 런타임 문제를 초래했습니다:

enum E { A, B } const f: (e: E) => void = (e: E.A) => {} // strictFunctionTypes 없이: 허용됨

strictFunctionTypes는 선택적 매개변수를 가진 콜백에 어떤 영향을 미치나요?

콜백 함수의 매개변수가 필수 매개변수를 선택적으로 만드는 경우, 엄격한 검사는 더 많은 필수 매개변수를 기대하는 위치에서 더 적은 필수 매개변수를 가진 함수를 사용할 수 없도록 합니다. 이는 콜백이 필요한 데이터를 받지 못하는 상황을 방지합니다.

오래된 프로젝트에서 strictFunctionTypes를 활성화하면 호환성 문제를 초래할까요?

네, 많은 함수와 핸들러가 반공변성 위반으로 서로 할당되었을 가능성이 있어 새로운 컴파일 오류가 발생할 위험이 있습니다. 이는 종종 콜백이나 외부 라이브러리 API를 사용할 때 더 자주 발생합니다.

일반적인 오류 및 안티패턴

  • 엄격한 매개변수 검사가 없는 구식의 콜백 타이핑 사용
  • 더 구체적인/좁은 매개변수 타입의 함수를 더 일반적인 핸들러에 할당하려는 시도
  • strictFunctionTypes 활성화 시 오류 무시(타입 수정 대신 옵션 주석 처리)

실제 사례

부정적인 케이스

대규모 프로젝트에서 이벤트 핸들러가 더 구체적인 타입(MouseEvent 대신 일반적인 Event)을 받습니다. 이는 엄격한 옵션을 활성화할 때까지 발견되지 않으며, 다양한 이벤트 소스에서 실행 시 오류를 초래합니다.

장점:

  • 더 빠른 프로토타이핑

단점:

  • 이벤트 타입 불일치로 인한 런타임 버그
  • 코드 확장 후 디버깅 복잡성 증가

긍정적인 케이스

프로젝트는 처음부터 strictFunctionTypes를 사용합니다. 새로운 핸들러를 추가할 때 컴파일러가 타입 간 불일치를 자동으로 발견합니다. 코드는 오타에 대해 더 견고하고 유지 관리가 용이해집니다.

장점:

  • 신뢰성
  • 함수 및 핸들러 전달의 안전성
  • 리팩토링 시 예측 가능한 동작

단점:

  • 서명 설계에 대한 철저한 요구
  • 경우에 따라 호환성을 위해 추가 래퍼나 오버로드 작성 필요