types - 可用於函數聲明的函數回調的 TypeScript 類型定義
是否有可能在 Typescript 中為回呼函數打上類型,以在型別系統中編碼以下兩個不變式:
- 如果 err == null,則 x 的類型是
T - 如果 err != null,則 x 不應被引用 (
從不?)
type Callback<T> = {
(error: null, value: T): void;
(error: Error): void;
};
// The function that takes the typed callback.
function incrementAsync(x: number, cb: Callback<number>): void {
if (x === 0) {
return cb(new Error());
}
cb(null, x + 1); // should type-check
cb(new Error()); // should type-check
cb(new Error(), 1) // should fail type-check
cb(null); // should fail type-check
}
這是我真正想要的函數簽名:
// Error: This overload signature is not compatible
// with its implementation signature.
function definedCb1(e: Error);
function definedCb1(e: null, x: number): void {}
incrementAsync(10, definedCb1); // error with strictNullChecks
這裡有一個較寬鬆的函數簽名,可以進行類型檢查
// BAD because types are too loose but this passes type-check.
function definedCb2(e: Error|null, x?: number): void {
if (e === null) {
// Is there a way to type this function, so the ! is not necessary?
console.log(x! + 1);
return;
}
// error because x might be undefined.
console.log(x + 2);
}
incrementAsync(20, definedCb2) // Works
Typescript Playground 連結啟用 strictNullChecks 和 noImplicitAny。
答案#1
如果你啟用 strictNullChecks,那麼這就符合你的需求。
interface Callback<T> {
(error: Error): void;
(error: null, value: T): void;
}
function incrementAsync(x: number, cb: Callback<number>): void {
cb(new Error()); // works
cb(null, x + 1); // works
cb(null); // error
cb(new Error(), 'foo'); // error
cb(null, 'foo'); // error
cb(new Error(), 10); // error
}
這裡在遊樂場。
strictNullChecks 標誌防止所有類型成為可為 null 的類型。
