簡體   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