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

TypeScript中编辑Record时如何正确推断Generic Key类型?

问题:配置泛型实现不可变布尔记录更新函数

我需要实现一个不可变更新布尔记录的函数,接收布尔值类型的Record和一组匹配键,返回新Record并将指定键的值设为true。但当前泛型配置导致编译错误——TypeScript仅从keys推断Key类型,而非同时从flags对象推断,导致flags包含不在keys中的属性时报错。

原错误代码

function createNextFlags<Key extends string>(
  flags: Record<Key, boolean>,
  ...keys: [Key, ...Key[]]
) {
  const nextFlags = {
    ...flags
  }
  for (const key of keys) {
    nextFlags[key] = true;
  }
  return nextFlags;
}

createNextFlags({
  vanilla:false,
  chocolate:true, // 该行因flags约束过窄产生编译错误
}, "vanilla")

尝试的解决方案

显式定义Flags泛型

尝试引入Flags泛型区分记录类型,但赋值操作触发错误:

// 显式定义Flags
function createNextFlags<Flags extends Record<Key, boolean>, Key extends string>(
  flags: Flags,
  ...keys: [Key, ...Key[]]
) {
  const nextFlags = {
    ...flags
  }
  for (const key of keys) {
    nextFlags[key] = true; // 该赋值操作被判定为非法!
  }
  return nextFlags;
}

createNextFlags({
  vanilla:false,
  chocolate:true,
}, "vanilla")

报错信息:

const nextFlags: Flags extends Record<Key, boolean>
Type 'boolean' is not assignable to type 'Flags[Key]'

使用keyof推导键

尝试直接用keyof Flags约束keys,仍出现类似错误:

// 使用keyof确保属性名称一致
function createNextFlags<Flags extends Record<any, boolean>>(
  flags: Flags,
  ...keys: [keyof Flags, ...(keyof Flags)[]]
) {
  const nextFlags = {
    ...flags
  }
  for (const key of keys) {
    nextFlags[key] = true;
  }
  return nextFlags;
}

报错信息:

const nextFlags: Flags extends Record<any, boolean>
Type 'boolean' is not assignable to type 'Flags[keyof Flags]'

使用infer推导键

尝试通过infer提取键类型,错误依旧:

type InferKey<Flags extends Record<any, boolean>> = Flags extends Record<infer Key, boolean> ? Key: never;

function createNextFlags<Flags extends Record<any, boolean>>(
  flags: Flags,
  ...keys: [InferKey<Flags>, ...InferKey<Flags>[]]
) {
  const nextFlags = {
    ...flags
  }
  for (const key of keys) {
    nextFlags[key] = true;
  }
  return nextFlags;
}

报错信息:

const nextFlags: Flags extends Record<any, boolean>
Type 'boolean' is not assignable to type 'Flags[InferKey<Flags>]'

正确解决思路与代码

核心问题是:当Flags为具体对象类型时,TypeScript无法确定Flags[Key]必然是boolean(比如属性可能是true/false字面量类型)。需要明确约束keys来自flags的键,并构造精确的返回类型。

精确实现版本

function createNextFlags<Flags extends Record<string, boolean>, K extends keyof Flags>(
  flags: Flags,
  ...keys: K[]
): Omit<Flags, K> & Record<K, true> {
  const nextFlags = { ...flags } as Omit<Flags, K> & Record<K, true>;
  for (const key of keys) {
    nextFlags[key] = true;
  }
  return nextFlags;
}

// 调用示例
const updated = createNextFlags({
  vanilla: false,
  chocolate: true,
}, "vanilla");
// updated类型:{ chocolate: boolean; } & { vanilla: true; }

简化实现版本

如果不需要精确的字面量类型,仅保证所有属性为boolean:

function createNextFlags<Flags extends Record<string, boolean>>(
  flags: Flags,
  ...keys: (keyof Flags)[]
): Record<keyof Flags, boolean> {
  const nextFlags = { ...flags } as Record<keyof Flags, boolean>;
  for (const key of keys) {
    nextFlags[key] = true;
  }
  return nextFlags;
}

关键说明

  1. 泛型K extends keyof Flags确保keys只能是flags已存在的键,实现keys从flags推断类型的需求
  2. 通过Omit<Flags, K> & Record<K, true>构造返回类型,明确标记指定键为true,其余属性保留原类型
  3. 使用类型断言as让TypeScript接受赋值操作——我们明确知道将指定键设为true符合返回类型定义

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 08:27:04