typescript 如何推断重载回调的参数类型?

ogq8wdun  于 2022-12-14  发布在  TypeScript
关注(0)|答案(1)|浏览(203)

我尝试在typescript中定义一个类型安全的nodejs样式的回调。我希望将err定义为Error(如果存在)或data定义为T(如果不存在)。
1.如果我用这个代码

export interface SafeCallback<T> {
    (err: unknown): void;
    (err: undefined, data: T): void;
}

const subscribe = <T>(callback: SafeCallback<T>) => {
    let result: T;
    try {
        // result = something
    } catch (e) {
        callback(e);
        return;
    }

    callback(undefined, result);
};

subscribe<{id: string}>((err, data?) => {
    if (!err) {
        console.log(data.id);
    }
});

我得到'data' is of type 'unknown'.
1.如果去掉data中的问号,则得到Argument of type '(err: undefined, data: { id: string; }) => void' is not assignable to parameter of type 'SafeCallback<{ id: string; }>'
我尝试了在第一个重载中定义err: Error的两种情况,但没有任何改变。
还有什么我该试试的吗?
谢谢你!

knpiaxh1

knpiaxh11#

有条件的类型可能是什么

export type SafeCallback<T> = {
    <errorType>(err: errorType, data: errorType extends undefined ? T : null): void;
};

const subscribe = <T>(callback: SafeCallback<T>) => {
    let result: T;
    try {
      // result logic
    } catch (e) {
        callback(e, null);
        return;
    }

    callback(undefined, result);
};

subscribe<{ id: string }>((err, data) => {
    if (data !== null) {
        console.log("data  = " + data.id);
    } else {
        console.log("err = " + err);
    }
});

编辑:刚刚看到@jclaz的回复。从他的回复中得到一些东西:

export interface SafeCallback3<T> {
    <errorType>(...args:( errorType extends undefined ? [err: undefined, data: T] : [err: errorType] )): void;
}

从而防止在捕获时发生投错。

const subscribe3 = <T>(callback: SafeCallback3<T>) => {
    let result: T;
        try {
        // ...
        } catch (e) {
            callback(e);
            return;
    }

    callback<undefined>(undefined, result);
};

subscribe3<{ id: string }>((...args) => {
  const [err, data] = args;
  if (!err) {
    console.log(data.id);
  } else {
    err.message
  }
});

相关问题