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

为何模板字面量类型无法用于对象属性名?如何为函数添加正确类型?

问题描述

我有如下简单JavaScript函数:

function retObj(suff, n) {
  const r = {[`fixed${suff}`]: n * 2};
  return r;
}

retObj('A', 3) // { fixedA: 6 }

尝试为其添加TypeScript类型定义时,编写了如下代码:

type FixedWithSuffix<T extends string> = `fixed${T}`;

type ObjWithFixedField<T extends string> = {[k in FixedWithSuffix<T>]: number};

function retObj<T extends string>(suff: T, n: number): ObjWithFixedField<T> {
  return {[`fixed${suff}`]: n * 2};
}

开启严格模式后,编译器报错:

Type '{ [x: string]: number; }' is not assignable to type '{ [k in `fixed${T}`]: number; }'.(2322)

但返回字符串的类似场景却可以正常工作:

type FixedWithSuffix<T extends string> = `fixed${T}`;

function retStr<T extends string>(suff: T): `fixed${T}` {
  return `fixed${suff}`;
}
报错原因

TypeScript对模板字面量的类型推断逻辑在字符串和对象场景下存在差异:

  • 返回字符串时,fixed${suff}会被精准推断为fixed${T}模板字面量类型,因为TS能直接关联模板表达式的泛型类型;
  • 返回对象时,使用计算属性创建的对象,其键的类型会被默认拓宽为string——TS无法确保运行时该键不会被修改,所以采用更宽泛的类型兜底,导致返回值类型{ [x: string]: number }和预期的ObjWithFixedField<T>不匹配,触发报错。
正确的类型定义方案

以下是几种可行的解决方式:

方案1:直接使用类型断言

明确告知编译器返回对象的类型与目标类型匹配:

type FixedWithSuffix<T extends string> = `fixed${T}`;
type ObjWithFixedField<T extends string> = {[k in FixedWithSuffix<T>]: number};

function retObj<T extends string>(suff: T, n: number): ObjWithFixedField<T> {
  return {[`fixed${suff}`]: n * 2} as ObjWithFixedField<T>;
}

方案2:借助Object.assign创建对象

Object.assign的类型推断能更好地保留计算属性的字面量类型:

type FixedWithSuffix<T extends string> = `fixed${T}`;
type ObjWithFixedField<T extends string> = {[k in FixedWithSuffix<T>]: number};

function retObj<T extends string>(suff: T, n: number): ObjWithFixedField<T> {
  return Object.assign({}, {[`fixed${suff}`]: n * 2}) as ObjWithFixedField<T>;
}

方案3:先约束键的类型再创建对象

先把模板字符串的键约束为目标字面量类型,再生成对象:

type FixedWithSuffix<T extends string> = `fixed${T}`;
type ObjWithFixedField<T extends string> = {[k in FixedWithSuffix<T>]: number};

function retObj<T extends string>(suff: T, n: number): ObjWithFixedField<T> {
  const key = `fixed${suff}` as FixedWithSuffix<T>;
  const obj = { [key]: n * 2 } as ObjWithFixedField<T>;
  return obj;
}

方案4:利用TS 4.4+的as const约束

在TS 4.4及以上版本,可通过as const直接限制计算属性的键类型:

type FixedWithSuffix<T extends string> = `fixed${T}`;
type ObjWithFixedField<T extends string> = {[k in FixedWithSuffix<T>]: number};

function retObj<T extends string>(suff: T, n: number): ObjWithFixedField<T> {
  return {[`fixed${suff}` as const]: n * 2} as ObjWithFixedField<T>;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 17:40:46