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

如何从已声明为Interface的对象键创建TypeScript新类型?

解决方案

问题出在你给allCodes显式标注了List类型,而List的索引签名是[key: string],这会让TypeScript丢失具体的键名信息,把allCodes的类型宽泛化为「任意字符串键对应ListField」,所以keyof typeof allCodes得到的是string | number而非你需要的具体键名联合类型。

下面是几种可行的实现方式:

方式一:去掉显式类型标注

直接让TypeScript自动推断allCodes的具体类型,这样就能保留所有键名信息:

interface ListField {
  code: number;
  message: string;
}

export const allCodes = {
  FIRST: {
    code: 1,
    message: 'message 1',
  },
  SECOND: {
    code: 2,
    message: 'message 2',
  },
  THIRD: {
    code: 3,
    message: 'message 3',
  },
};

export type ListType = keyof typeof allCodes; // 类型为 "FIRST" | "SECOND" | "THIRD"

方式二:保留类型约束的同时推导键名

如果需要确保allCodes的结构符合ListField的要求,可以用泛型函数来创建它,既约束值的类型,又保留具体键名:

interface ListField {
  code: number;
  message: string;
}

function createCodes<T extends Record<string, ListField>>(codes: T) {
  return codes;
}

export const allCodes = createCodes({
  FIRST: {
    code: 1,
    message: 'message 1',
  },
  SECOND: {
    code: 2,
    message: 'message 2',
  },
  THIRD: {
    code: 3,
    message: 'message 3',
  },
});

export type ListType = keyof typeof allCodes; // 得到目标联合类型

方式三:使用const断言+satisfies(TypeScript 4.9+)

这种方式既可以用const断言锁定键名和值的类型,又通过satisfies确保结构符合ListField的约束:

interface ListField {
  code: number;
  message: string;
}

export const allCodes = {
  FIRST: {
    code: 1,
    message: 'message 1',
  },
  SECOND: {
    code: 2,
    message: 'message 2',
  },
  THIRD: {
    code: 3,
    message: 'message 3',
  },
} as const satisfies Record<string, ListField>;

export type ListType = keyof typeof allCodes;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 23:54:52