通常你会使用一个参数受歧视联盟 https://www.typescriptlang.org/docs/handbook/advanced-types.html#discriminated-unions类型而不是两个联合类型参数,例如err
and data
其类型彼此相关。
TypeScript 确实没有太多支持相关表达; see 微软/TypeScript#30581 https://github.com/Microsoft/TypeScript/issues/30581。也就是说,没有一个很好的方法来告诉编译器,虽然err
属于类型Error | null
而同时data
属于类型Buffer | undefined
,一些类型的组合err
and data
是不可能的。您可以使用控制流分析 https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#control-flow-based-type-analysis检查类型err
,但不会影响感知类型data
...编译器错误地假设它们是独立的表达式。
这是我能得到的最接近的;它大量使用休息和扩展表达式中的元组 https://github.com/Microsoft/TypeScript/wiki/What%27s-new-in-TypeScript#tuples-in-rest-parameters-and-spread-expressions你真的必须与编译器斗争才能让它发生:
declare function myFunction(
someString: string,
someCallback: (...args: [Error, undefined] | [null, Buffer]) => void
): void;
的类型someCallback
是一个只有两个参数的函数,这两个参数要么是类型[Error, undefined]
或键入的[null, Buffer]
。现在轮到你can使用两个参数回调来调用它,但是您将遇到与已经遇到的完全相同的问题:检查err
没有做任何事data
:
// can't call it this way
myFunction("oops", (err, data) => {
err; // Error | null
data; // Buffer | undefined
if (err) {
data; // still Buffer | undefined ????
}
});
相反,您还必须在回调实现中使用剩余参数:
myFunction("foo", (...errData) => {
if (errData[0]) {
const [err, data] = errData;
err; // Error
data; // undefined
} else {
const [err, data] = errData;
err; // null
data; // Buffer
}
});
这是有效的,因为当你检查时errData[0]
您正在检查元组对象的单个属性,编译器将使用控制流分析来缩小范围errData
为两种已知类型之一。你只能打破errData
出入err
and data
after支票。
我强烈建议您考虑在回调中切换到单个可区分的联合参数。看看这个解决方案是多么简单:
type Param = { type: "Error"; err: Error } | { type: "Data"; data: Buffer };
declare function myFunction(
someString: string,
someCallback: (param: Param) => void
): void;
myFunction("foo", param => {
if (param.type === "Error") {
param.err; // Error
} else {
param.data; // Buffer
}
});
这正是你想要的,不需要战斗。
链接到代码 https://www.typescriptlang.org/play/#code/C4TwDgpgBAQgrgMwRATlAvFA3lARohEALigGdgUBLAOwHMoBfAbgFgAod6gQwFsJSwXAMbQAKgAsIAYQA2Ae1L9gASSldqAcQjAA6pWDjRAdzkAFLil7bUpbOyhQAJhCEyL0BHGpDglOdSgeEAAxLx8-agAKewcyOT4AZQoaWhJyKjoAGhiHUnjpLhkZXGEAaxJIgDpqi1pSEgBtAFEUFDkUTKgvZwQaCEcAXSgAHygG6jgizvgkVAGASgwAPigANzlKRxj5knXN1g42BwB6Y6ghdQByYHPCmSh9KANKWyMuEBig0O9ff0iAIjkcjApH+nUiqA6Ti4wC4i3QKywOSgkKYUFOUBabTQowmRWRjhhXDRGJmyBxXWoPT6WyOsUoCCgENaiyRdNi0NhJLO5EoRVgBFQI0p1Oo-SggF4NwD4e8iGDEGPMDjEMeIuKtoMA5Ld+Y9nq93p8QmFflF-gggWCmdVKpCACJE+GI5EMpl2okNAAMCzs7NiQn85DGkM6hNhQ0wbq5yIcqPRZyx7WjnOJcZFEF6YtpHIYKJkih9HIc-uogYaweT4ZRrXtUd9Mda3KgeJkSdDKdJgpQsvlivYcsO3D4AmE0FtLyEVB4NBh-QAqtQIgWnuBoOZLDwMNhl5ASP8Eyh-mjISR94xhThQDuoP8a1xD8mSGShcwYs5XO4oJ4fouvsaItFfTyRJkjoNIQNobJAPyNQihKIRyiZQR1xINdeEdNYNizKAdgw-Z2ENb5wj+M0LU6JDeGWJcHBdSJyJ4SpL2gdBmOvfd-lZJM6JtBtU33WVc3zNlCygLi20bJ8u19fsHAVA5+yAA