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

如何用TypeScript泛型验证keyof的所有键都已指定?

如何在TypeScript中强制对象所有键必须分配到查询或修改参数中?

我写了一个辅助函数,用于包装对象并根据键属于查询函数还是修改函数来处理所有键。现在需要编写TypeScript类型声明,确保对象的所有键都必须被指定到queries或mutations两个参数中的某一个里。

当前代码

我现在的函数声明如下:

function createService<
    T,
    Q extends keyof T,
    M extends Exclude<keyof T, Q>,
>(obj: T, queries: readonly Q[], mutations: readonly M[]) {}

这段代码能验证同一个键不能同时出现在两个参数中,但无法确保所有键都被分配到其中一个参数里。

示例用法

interface Test {
  a: () => void;
  b: () => void;
}
const obj: Test = { a: () => {}, b: () => {} };

// 符合要求的调用
createService(obj, ["a"], ["b"]);
createService(obj, ["a", "b"], []);

// 错误情况
createService(obj, ["a", "b"], ["b"]); // 当前代码已能检测:"b"重复设置
createService(obj, ["a"], []); // 无报错但应该报错:"b"未被分配
createService(obj, [], ["b"]); // 无报错但应该报错:"a"未被分配

尝试过的无效写法

我试过添加一个泛型检查,但无法通过编译:

function createService<
    T,
    Q extends keyof T,
    M extends Exclude<keyof T, Q>,
    CHECK extends never = Exclude<keyof T, Q | M>, // 编译错误:Type 'string' is not assignable to type 'never'
>(obj: T, queries: readonly Q[], mutations: readonly M[]) {}

解决方案

可以通过泛型约束来强制Q | M完全覆盖keyof T,也就是确保所有键都被分配到两个参数中的一个。以下是可行的写法:

function createService<
    T,
    Q extends keyof T,
    M extends Exclude<keyof T, Q>,
    _ extends never = Exclude<keyof T, Q | M>
>(obj: T, queries: readonly Q[], mutations: readonly M[]) {}

原理说明

这个写法的核心是:如果存在未被分配的键,Exclude<keyof T, Q | M>会返回这些未分配的键组成的联合类型,而这个类型无法赋值给never,因此会触发编译错误。这样就能同时满足两个需求:

  1. 同一个键不能同时出现在queries和mutations中(原有逻辑已实现)
  2. 对象的所有键必须被分配到其中一个参数里(新增约束实现)

测试后可以看到,之前未分配键的情况会正确报错,重复键的情况依然会被检测到,完全符合需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 18:23:14