0

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()and getHeaders(),因为它们是object | FormData, not FormData。另外,如果不直接投射,我该怎么办(<FormData>obj).getBuffer()

4

1 回答 1

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合理的。看看与该行为完全相同的类似问题 -这里

于 2020-03-15T14:57:39.833 回答