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