You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 23:41:31