문제의 역사: JavaScript에서는 콜백 함수가 널리 사용되지만 그 시그니처는 자주 명확하지 않습니다. TypeScript에서는 매개변수 및 반환 값의 타입을 명시적으로 지정해야 하며, 그렇지 않으면 타입 안전성에 구멍이 생기기 쉽습니다.
문제: 잘못되거나 느슨한 콜백 타입 지정은 인수 및 결과의 불확실한 타입으로 이어지며, 컨텍스트(this)를 다루는 것을 복잡하게 만들고, 컴파일러의 자동 오류 검사 기능을 방해하며, 리팩토링을 어렵게 만듭니다.
해결책: 콜백 함수의 타입을 명시적으로 정의하고, 전달된 매개변수의 타입을 명시하며, 선택적 인수를 올바르게 처리하고 반환 값을 정의해야 하며, 필요시 컨텍스트의 타입을 명시적으로 지정해야 합니다.
코드 예시:
type Callback = (error: Error | null, result?: string) => void; function doAsyncWork(data: string, cb: Callback): void { setTimeout(() => { if (data === '') cb(new Error('빈 문자열')); else cb(null, data.toUpperCase()); }, 100); }
주요 특징:
콜백의 반환 타입을 지정하지 않으면 어떻게 되나요?
TypeScript는 어떤 반환 타입이든 허용합니다 (예: undefined, void, Promise), 이는 비동기 체인에서 놀라운 결과로 이어질 수 있으며, "기본값"을 반환할 때 문제가 발생할 수 있습니다.
type BadCallback = (data: string) => any; // 아무런 결과, 통제 없음
Function 또는 (...args: any[]) => any로 콜백을 쓸 수 있나요?
안 됩니다. 이는 모든 타입 보호를 제거하고, 매개변수의 수와 타입, 반환 타입에 대한 정보를 잃게 됩니다. 이러한 접근 방식은 TypeScript를 전혀 사용하지 않는 것보다 비용이 더 많이 듭니다.
this 컨텍스트가 있는 함수는 어떻게 타입을 지정하나요?
함수 시그니처에서 첫 번째 매개변수 this를 사용하거나 bind를 통해 캐스팅하세요. 예:
interface ClickCallback { (this: HTMLElement, event: MouseEvent): void; } const handler: ClickCallback = function (event) { this.textContent = 'ok'; };
프로젝트에서 콜백을 (...args: any[]) => any으로 선언했습니다. 비즈니스 로직이 변경되면서 시그니처가 변경되었고, 콜백이 필요한 인수를 전달하지 않게 되어, 버그가 프로덕션에서만 발생했습니다.
장점:
단점:
엄격한 타입을 도입했습니다: 콜백의 인터페이스를 정의하고 this 및 반환 타입을 명시적으로 지정하기 시작했습니다. 컴파일러가 배포 전에 오류를 잡아내면서 리팩토링과 버그 수정이 쉬워졌습니다.
장점:
단점: