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

如何提取带索引签名类型中的已定义键?

问题:如何创建类型转换器提取带索引签名对象类型的已定义键?

TL;DR

需要实现一个TypeScript类型转换器,接收类型A后返回类型B——B包含A的所有已定义键,且值仅接受string类型。但当A带有索引签名时,当前实现无法正确提取已定义的具体键。


普通对象类型下的可行实现

我原本写的类型转换器在普通对象场景可以正常工作:

type AToB<
   T,
   K extends keyof T = keyof T
> = { [id in K]: string };

const a = {
    x : {}
}

const b : AToB<typeof a> = {
    x : "这里可以正常识别键x"
}

此时b的类型推导正常,能正确识别键x

带索引签名的对象类型出现问题

但当对象类型带有索引签名时,keyof无法获取到已定义的具体键:

type AWithSig = {
    [id : string]: {};
}

const aSig : AWithSig = {
    y: {},
    z: {}
}

const bSig : AToB<typeof aSig> = {
    y : "这里无法识别键y",
    z : "键z也不会被提示 :("
}

此时bSig无法识别y和z这两个已定义的键,但如果手动给类型指定具体键的话就能正常工作。


解决方案

问题核心在于:当给变量显式指定带索引签名的类型(比如AWithSig)后,TypeScript会丢弃具体的键信息,只保留索引签名的类型约束。要保留对象的具体键,需要让TypeScript自动推导类型,同时确保它符合索引签名的约束。

方案1:用satisfies保留推导类型 + 约束

让变量自动推导具体键,同时用satisfies确保它符合索引签名的规则:

type AWithSig = {
    [id : string]: {};
}

// 自动推导aSig的具体键,同时约束它符合AWithSig的规则
const aSig = {
    y: {},
    z: {}
} satisfies AWithSig;

// 原有的AToB可以直接正常使用
const bSig : AToB<typeof aSig> = {
    y: "现在能识别键y了",
    z: "键z也会自动提示!"
};

方案2:修改AToB适配带具体键的索引签名类型

如果需要更通用的类型转换器,可以调整AToB,确保它能提取带索引签名类型中的具体键(前提是类型本身保留了具体键信息):

type AToB<T> = {
    [K in keyof T]: string;
}

type AWithSig = {
    [id : string]: {};
}

// 同样需要保留具体键的推导
const aSig = {
    y: {},
    z: {}
} satisfies AWithSig;

const bSig : AToB<typeof aSig> = {
    y: "正常工作",
    z: "完美识别"
};

关键原理

  • 显式指定带索引签名的类型时,TypeScript会将变量类型“收窄”到索引签名,丢失具体键的信息;
  • satisfies关键字可以在保留自动推导的具体键的同时,确保变量符合目标类型的约束;
  • keyof处理带索引签名的类型时,默认只会返回索引签名的键类型(比如string),只有当类型本身保留了具体键时,才会返回这些具体键。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 12:33:13