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

问题描述 投票:0回答:1

我正在尝试在打字稿中定义类型安全的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
的两种情况,但它没有改变任何东西。

我还应该尝试什么吗?

谢谢!

typescript callback type-safety
1个回答
0
投票

也许有条件类型?

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);
    }
});

编辑:刚刚看到@jcalz 回复。从他的回复中获取一些信息:

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

防止在 catch 中抛出错误。

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
  }
});
© www.soinside.com 2019 - 2024. All rights reserved.