[英]TypeScript union type narrowing and assignment problem
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
object | FormData
,而不是FormData
。 另外,如果不直接转换(<FormData>obj).getBuffer()
,我该怎么办?
该问题与 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
是合理的。 看看与该行为类似的问题 - 在这里
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.