如何在TypeScript类型系统中缩小联合类型范围?
TypeScript类型系统中如何从联合类型提取特定分支?
我有联合类型 {error:true} | {error:false},希望仅通过TypeScript类型系统将其转换为 {error: true} 类型。我知道运行时可以通过if语句做类型收窄:
const x: {error:true} | {error:false} = {error:true} if (x.error) { // x 被收窄为 {error: true} 类型 } else { // x 被收窄为 {error: false} 类型 }
但不确定仅靠类型系统能否实现,特此请教。
实际场景
我多次遇到这类类型收窄的需求,最近一次是API返回类型为 ErrorType | SuccessType,需要分别为错误回调和成功回调指定 ErrorType 和 SuccessType 类型。具体代码如下:
声明API契约
export const API_FORM_TAG_SET = createFormUrl( '/api/forms/tag/set', z.object({thing_id: z.string().uuid()}), z.array(z.object({tag_id: z.string(), value: z.boolean()}))) <{ errors: string[] }, { tags: {[key:string]:tag} }>();
createFormUrl 定义
export type FormErrorType = { errors: string[] }; export type FormUrl<Q, B, ErrorType, SuccessType> = ApiUrl<Q, B, (ErrorType & FormErrorType) | SuccessType>; export function createFormUrl<ZQ extends Zod.Schema, ZB extends Zod.Schema>(path, querySchema: ZQ, bodySchema: ZB) : <E, S>() => FormUrl<getZodType<ZQ>, getZodType<ZB>, E, S> { type Q = getZodType<ZQ>; type B = getZodType<ZB>; return <E, S>(): FormUrl<Q, B, E, S> => { return new ApiUrl<Q, B, (E & FormErrorType) | S>(path, querySchema, bodySchema); } }
客户端使用契约
const handleSubmit = createHandleSubmit(API_FORM_TAG_SET, (element) => tags.map(({tag_id}) => ({tag_id, value: !!(element[tag_id].checked)})), (res) => setErrors(res.errors), (res) => { setTagState(res.tags)}, {thing_id});
createHandleSubmit 定义
export function createHandleSubmit<Q,B,E,S>(apiUrl: FormUrl<Q, B, E, S>, formToData: (element: HTMLElement) => B, reject: (res: E & FormErrorType) => void, resolve: (res: S) => void, query?: Q){ return async (event) => { event.preventDefault(); const data = formToData(event.target); const res = await apiUrl.post(query as Q, data as B); if ("errors" in res.data) { reject(res.data); } else { resolve(res.data); } } }
后续发现,通过在表单工具中使用 Extract<ResponseType, FormErrorType>,可以避免创建FormUrl类型及对应的创建函数(感谢@jcalz)。
内容的提问来源于stack exchange,提问作者evandwight
相关产品推荐
相关产品推荐

