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

TypeScript中如何以类型为对象键?示例代码报错求解

TypeScript字体测量层级类型约束问题解决方案

问题背景

需要实现带严格层级类型约束的measureText函数,要求调用时指定的字重必须属于对应字体族,字号必须属于对应字重,同时解决原代码中的类型错误问题。

原代码核心错误

  1. 枚举FontFamilyType的键与值类型不匹配,导致索引MEASUREMENTS时触发隐式any类型转换
  2. 泛型类型W被当作值使用,违反TypeScript类型与值分离的规则
  3. 原Record类型定义过于宽泛,丢失了MEASUREMENTS中具体的字重、字号字面量信息,削弱类型检查能力

修正后的完整实现

// 调整枚举值与MEASUREMENTS的键完全匹配
enum FontFamilyType {
  Matter = 'Matter',
  Inter = 'Inter',
}

// 用as const锁定字面量类型,保留所有层级的具体类型信息
const MEASUREMENTS = {
  [FontFamilyType.Matter]: {
    600: {
      36: { a: 10, b: 20 },
      30: { a: 8, b: 18 },
      24: { a: 6, b: 16 },
      18: { a: 5, b: 14 },
      16: { a: 4, b: 12 },
    }
  },
  [FontFamilyType.Inter]: {
    700: {
      36: { a: 11, b: 21 },
      24: { a: 7, b: 17 },
    },
    600: {
      20: { a: 6, b: 16 },
      18: { a: 5, b: 15 },
      15: { a: 4, b: 13 },
      13: { a: 3, b: 11 },
    },
    400: {
      20: { a: 5, b: 14 },
      18: { a: 4, b: 13 },
      15: { a: 3, b: 12 },
      13: { a: 2, b: 10 },
    },
  },
} as const;

// 基于MEASUREMENTS的实际类型推导层级类型
type Measurements = typeof MEASUREMENTS;
type WeightType<F extends FontFamilyType> = keyof Measurements[F];
type SizeType<F extends FontFamilyType, W extends WeightType<F>> = keyof Measurements[F][W];

function measureText<
  F extends FontFamilyType,
  W extends WeightType<F>,
  S extends SizeType<F, W>
>(text: string): void {
  // 通过类型断言解决泛型类型到值的索引匹配问题
  const sizeMeasurements = MEASUREMENTS[F as keyof Measurements][W as keyof Measurements[F]][S as keyof Measurements[F][W]];
  console.log('测量数据:', sizeMeasurements);
}

// 合法调用:类型检查完全通过
measureText<FontFamilyType.Matter, 600, 30>('foo');
// 非法调用:类型检查报错(600不属于Inter的字重)
// measureText<FontFamilyType.Inter, 600, 36>('bar');

关键修改说明

  1. 锁定字面量类型:

    • 给MEASUREMENTS添加as const,让TypeScript保留所有层级的具体字面量类型(如600、30等),而非自动推断为宽泛的string或number
    • 枚举值与MEASUREMENTS的键完全对齐,避免索引时的类型不匹配
  2. 解决类型与值混用问题:

    • 通过类型断言F as keyof Measurements将泛型类型转换为可用于索引的键类型,绕过TypeScript的严格索引检查(因泛型仅在编译期存在,运行时无对应值)
  3. 精确层级类型推导:

    • 基于MEASUREMENTS的实际类型自动推导WeightType和SizeType,确保字重必须属于指定字体族,字号必须属于指定字重,实现严格的层级约束

更直观的替代实现(推荐)

如果允许将字体族、字重、字号作为函数参数传入,可避免类型断言,代码更直观:

const MEASUREMENTS = {
  Matter: {
    600: {
      36: { a: 10, b: 20 },
      30: { a: 8, b: 18 },
    }
  },
  Inter: {
    700: {
      36: { a: 11, b: 21 },
    },
  },
} as const;

type FontFamily = keyof typeof MEASUREMENTS;
type Weight<F extends FontFamily> = keyof typeof MEASUREMENTS[F];
type Size<F extends FontFamily, W extends Weight<F>> = keyof typeof MEASUREMENTS[F][W];

function measureText<F extends FontFamily, W extends Weight<F>, S extends Size<F, W>>(
  fontFamily: F,
  weight: W,
  size: S,
  text: string
): void {
  const sizeMeasurements = MEASUREMENTS[fontFamily][weight][size];
  console.log('测量数据:', sizeMeasurements);
}

// 合法调用
measureText('Matter', 600, 30, 'foo');

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 06:12:09