TypeScript可以使用以下示例代码正确缩小联合类型:
interface Callable {
call(): void
}
declare function getCallable(): Callable
let x: string | Callable = { call(){} }
if (typeof x === 'string') {
x = getCallable()
// `x` can only be `Callable` here
}
x.call()
但是它在实际代码上不起作用,类似于上面的代码:
form(obj: object | FormData): Request {
if (!(obj instanceof FormData)) {
const form = new FormData()
for (const [k, v] of Object.entries(obj)) {
form.append(k, v)
}
obj = form
}
// `obj` must be FormData here, but why `obj` is still `object | FormData`?
const stream = new Readable()
stream.push(obj.getBuffer()) // FormData has getBuffer() and getHeaders()
this._body = stream
this.header(obj.getHeaders())
return this
}
我认为!(obj instanceof FormData)
意味着只有object
可以进入if
块,并且obj
在那里被分配给FormData
,所以obj
必须为FormData
。
但是TypeScript编译器抱怨obj
没有getBuffer()
和getHeaders()
,因为它们是object | FormData
,而不是FormData
。另外,如果不直接像(<FormData>obj).getBuffer()
一样投射怎么办?
答案 0 :(得分:2)
问题与TS如何处理参数有关。它们被视为const
,而不是let
。这意味着TS不会遵循参数的重新分配。当然,您可以这样做,因为在运行时有可能(不重新分配const),但是TS处于参数的“ const模式”。解决方案是临时变量:
function form(obj: object | FormData): Request {
let finalObj: FormData;
if (!(obj instanceof FormData)) {
const form = new FormData()
for (const [k, v] of Object.entries(obj)) {
form.append(k, v)
}
finalObj = form
} else {
finalObj = obj;
}
// rest of the code should use finalObj
为什么TS会这样做-一般而言,重新分配参数不是一个好习惯,因此将其视为const
是合理的。看看与该行为完全相同的类似问题-here