질문의 역사
기본적으로 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를 사용할 때 더 자주 발생합니다.
대규모 프로젝트에서 이벤트 핸들러가 더 구체적인 타입(MouseEvent 대신 일반적인 Event)을 받습니다. 이는 엄격한 옵션을 활성화할 때까지 발견되지 않으며, 다양한 이벤트 소스에서 실행 시 오류를 초래합니다.
장점:
단점:
프로젝트는 처음부터 strictFunctionTypes를 사용합니다. 새로운 핸들러를 추가할 때 컴파일러가 타입 간 불일치를 자동으로 발견합니다. 코드는 오타에 대해 더 견고하고 유지 관리가 용이해집니다.
장점:
단점: