[英]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.