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

TypeScript泛型实现对象仅使用指定联合类型键、无需全量键且属性类型确定

需求说明

现有已知值的联合类型:

type Possibilities = "a" | "b" | "c"

需要实现类型约束,使得创建的对象仅能使用属于该联合类型的成员作为键,但无需包含全部键;同时要避免属性类型被推导为string | undefined。
类型推导为string|undefined的问题截图

该类型用于固定值的常量声明,TypeScript本身可对常量完成正确的类型推导:
常量正确类型推导截图

符合约束的合法示例如下:

const mine = {
    a: "this",
    b: "and",
    c: "that"
}
const yours = {
    b: "it"
}

不符合约束的非法示例如下:

// 存在不在联合类型中的未知键 'x'
const theirs = {
    a: "these",
    x: "those"
}
// 优先禁止空对象
const noOnes = {}

已尝试方案
  • 使用Record<Possibilities, string>或索引签名写法{[key in Possibilities]: string}标注类型时:
const mine: Record<Possibilities, string>;
const mine: {[key in Possibilities]: string};

TypeScript会要求对象必须包含所有指定键,不符合需求。

  • 使用Partial<Record<Possibilities, string>>或可选索引签名写法{[key in Possibilities]?: string}标注类型时:
const mine: Partial<Record<Possibilities, string>>;
const mine: {[key in Possibilities]?: string};

虽然允许仅传入部分键,但属性类型会被推导为string | undefined,即使给对象加上as const断言也无法解决该问题。

  • 对每个声明的对象单独使用Pick<>或Omit<>虽然可以得到预期结果,但使用成本极高,存在重复编码问题(需要在类型定义和值声明中重复书写"a", "b"...等值)。
    Pick/Omit方案问题截图
    同时该方案下Omit<>甚至无法触发可选值的自动补全,当需要使用大部分可选键时,需要手动Pick大量值或盲目Omit,极易出错。

目前猜测解决方案需要借助继承目标类型的泛型实现,但暂时没有找到正确的实现方式。

补充编辑

现有一个接近可用的方案实现如下:

type AtLeastOne<T, U = {[K in keyof T]: Pick<T, K> }> = Partial<T> & U[keyof U]

type Possibilities = "a" | "b" | "c"

let mine: AtLeastOne<Record<Possibilities, string>>;

该方案可以强制对象至少包含a/b/c中的一个属性,禁止传入未知属性,且已声明属性的类型不会被推导为“可能为undefined”:
单属性场景验证截图
未知键拦截截图
属性类型正确截图

但该方案存在缺陷:当对象设置多个允许的属性时,类型校验会报错:
多属性场景报错截图


内容的提问来源于stack exchange,提问作者Jonatas Amaral

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 02:27:31