繁体   English   中英

如何获取typescript 了解条件类型的使用

[英]How to get typescript to understand the use of a conditional type

我有一个用于验证收据的 post 端点的请求处理程序。 将两种类型之一作为传入有效负载的处理程序{location: 'foo' | 'bar', receipt: string | BarReceipt} {location: 'foo' | 'bar', receipt: string | BarReceipt} {location: 'foo' | 'bar', receipt: string | BarReceipt} 如果位置是foo那么收据总是string ,反之亦然,如果位置是bar那么收据总是BarReceipt 我正在尝试根据有效负载中的参数确定有效负载的类型,然后让 typescript 了解类型是什么而无需强制转换,但我无法弄清楚。

// types.ts

export interface ValidateTransactionRequest extends Request {
  payload: ValidateTransactionPayload
}
export type ExtractLocation<T> = T extends {
  payload: { location: Location.foo }
}
  ? { payload: FooTransactionPayload }
  : T extends {
      payload: { location: Location.bar }
    }
  ? { payload: BarTransactionPayload }
  : never

export const enum Location {
  foo = 'foo',
  bar = 'bar',
}

export type ValidateTransactionPayload =
  | FooTransactionPayload
  | BarTransactionPayload

export interface FooTransactionPayload {
  location: Location.foo
  receipt: string
}
export interface BarTransactionPayload {
  location: Location.bar
  receipt: BarReceipt
}

export interface BarReceipt {
  orderId: string
}

这是我希望 typescript 了解正在使用哪种类型的代码。

// handler.ts
async function handler<T extends ValidateTransactionRequest>(
    request: ExtractLocation<T>,
  ): Promise<VerificationResponse> {
    const { location, receipt } = request.payload

    if (location === Location.foo) {
       validateFooReceipt(receipt) // typescript warning type 'string | BarReceipt' is not assignable to type 'string'.
    } else if (location === Location.bar) {
      validateBarReceipt(receipt) // typescript warning type 'string | BarReceipt' is not assignable to type 'BarReceipt'.
    }
  }

function validateFooReceipt(receipt: string) {...}
function validateBarReceipt(receipt: BarReceipt) {...}

我可以在 if 语句的每个分支中转换有效负载的类型并继续我的生活,但我需要。 至。 知道。

很抱歉把酒吧收据留在了各处。

回答我自己的问题。

事实证明,在类型保护之前解构有效负载是这里的问题。 请参阅 github https 上的此线程://github.com/microsoft/TypeScript/issues/13403

我在这里的 typescript 操场上放了一个例子。

type ReceiptRequest = FooReceiptRequest | BarReceiptRequest

interface BarReceiptRequest { payload: { location: 'bar', receipt: BarReceipt } }

interface FooReceiptRequest { payload: { location: 'foo', receipt: string } }

interface BarReceipt {
  foo: number
}

const handlerWorks = (request: ReceiptRequest) => {
  if (request.payload.location === 'foo') {
    takesAString(request.payload.receipt)
  } else if (request.payload.location === 'bar') {
    takesBarReceipt(request.payload.receipt)
  }
  // type Error when outside of the type guard :)
  takesBarReceipt(request.payload.receipt)
}

const handlerNotWorking = (request: ReceiptRequest) => {
const {receipt, location} = request.payload

if (location === 'foo') {
  // type error "Argument of type 'string | BarReceipt' is not assignable to parameter of type 'string'."
  takesAString(receipt)
  } else if (location === 'bar') {
    // type error "Argument of type 'string | BarReceipt' is not assignable to parameter of type 'BarReceipt'."
    takesBarReceipt(receipt)
  }
}

function takesAString(receipt: string) {}

function takesBarReceipt(receipt: BarReceipt) {}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM