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

自定义类型断言守卫导致Builder的data字段为null问题求助

解决Builder类型断言后类型更新异常问题

问题根源

  1. UpdatedBuilderData泛型约束错误:原类型中CurrentData被约束为BuilderData<BuilderSchema>,丢失了当前具体Schema的类型关联,导致TypeScript无法正确计算更新后的Data类型。
  2. 显式固定变量类型:builder2被显式声明为Builder<typeof schema>,锁定了变量类型,类型断言无法修改显式指定的变量类型,必须让TypeScript自动推断类型才能让断言生效。

修正后的代码

type BuilderSchema = {
    [k in string]: {
        data: ReadonlyArray<string>
    }
}
type BuilderData<T extends BuilderSchema> = {
    [k in keyof T]: { value: T[k]["data"][number] } | null
}
// type helper for blank schema data
type NulledOutBuilderData<T extends BuilderSchema> = {
    [k in keyof T]: null
}
interface Builder<Schema extends BuilderSchema, Data extends BuilderData<Schema> = NulledOutBuilderData<Schema>> {
    _data: Data,
    // chaining
    setData: <
        const K extends keyof Schema,
        const Value extends Exclude<BuilderData<Schema>[K], null>["value"] | null
    >(key: K, value: Value) => Builder<Schema, UpdatedBuilderData<Schema, Data, K, Value>>
    // assertions
    setAndAssertData: <
        const K extends keyof Schema,
        const Value extends Exclude<BuilderData<Schema>[K], null>["value"] | null
    >(key: K, value: Value) => asserts this is Builder<Schema, UpdatedBuilderData<Schema, Data, K, Value>>
}
// 修正CurrentData的约束为BuilderData<Schema>,关联当前Schema的Data类型
type UpdatedBuilderData<
    Schema extends BuilderSchema,
    CurrentData extends BuilderData<Schema>,
    Key extends keyof Schema,
    NewValue extends Exclude<BuilderData<Schema>[Key], null>["value"] | null
> = {
    [k in keyof Schema & keyof CurrentData]:
        k extends Key
            ? NewValue extends null
                ? NewValue
                : { value: NewValue }
            : CurrentData[k]
}

const schema = {
    prop1: {
        data: [
            "hello",
            "world"
        ]
    },
    prop2: {
        data: ["foo", "bar", "baz"]
    }
} as const satisfies BuilderSchema

// function that returns a builder of the specified schema
declare function createBuilder<const Schema extends BuilderSchema>(schema: Schema): Builder<Schema>

// chaining. no problems
let builder1 = createBuilder(schema)
builder1.setData("prop1", "world").setData("prop2", "baz").setData("prop1", "hello")

// 去掉显式类型声明,让TypeScript自动推断
let builder2 = createBuilder(schema)
builder2.setAndAssertData("prop1", "world")
builder2._data
//          ^? { prop1: { value: "world" }; prop2: null }

关键修改说明

  • 修正UpdatedBuilderData的泛型约束:将CurrentData extends BuilderData<BuilderSchema>改为CurrentData extends BuilderData<Schema>,确保TypeScript能基于当前具体的Schema计算更新后的Data类型,避免类型丢失。
  • 移除显式变量类型声明:builder2不再显式指定Builder<typeof schema>类型,让TypeScript自动跟踪类型变化,这样setAndAssertData的断言才能正确更新变量的类型。

修改后,builder2._data的类型会正确显示为{ prop1: { value: "world" }; prop2: null },类型断言功能正常,同时保持了类型清晰和智能提示。

内容的提问来源于stack exchange,提问作者A Kam

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 22:30:58