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

创建新字面量类型时如何使用推断类型?

如何在约束对象类型的同时提取字面量联合类型?

问题场景

我定义了表示商店目录的StoreCatalog接口:

interface StoreCatalog {
  products: { name: string }[];
}

当给配置对象加上这个类型标注并使用as const时,尝试提取产品名称的字面量类型只能得到string,而非预期的"apples" | "bananas":

const groceryStoreConfig: StoreCatalog = {
  products: [{ name: "apples" }, { name: "bananas" }],
} as const;

// 实际得到类型:string
export type GroceryStoreProductNames =
  (typeof groceryStoreConfig)["products"][number]["name"];

如果移除类型标注,虽然能得到正确的字面量联合类型,但对象可以随意添加不符合StoreCatalog的属性,不会触发类型检查:

// 无类型约束,额外属性不会报错
const groceryStoreConfig = {
  products: [
    { name: "apples" },
    { name: "bananas", additionalProperty: "additional property" },
  ],
} as const;

// 得到预期类型:"apples" | "bananas"
export type GroceryStoreProductNames =
  (typeof groceryStoreConfig)["products"][number]["name"];

解决方案

方案1:使用satisfies关键字(TypeScript 4.9+)

satisfies关键字可以确保对象符合指定类型,同时保留其字面量的窄化类型信息,完美解决这个矛盾:

interface StoreCatalog {
  products: { name: string }[];
}

const groceryStoreConfig = {
  products: [{ name: "apples" }, { name: "bananas" }],
} as const satisfies StoreCatalog;

// 正确得到类型:"apples" | "bananas"
export type GroceryStoreProductNames = (typeof groceryStoreConfig)["products"][number]["name"];

// 尝试添加额外属性会触发类型错误
const invalidConfig = {
  products: [{ name: "apples", extra: "oops" }],
} as const satisfies StoreCatalog; 
// 错误提示:对象字面量只能指定已知属性,'extra' 不在类型 '{ name: string; }' 中

方案2:泛型函数约束(兼容低版本TS)

如果你的项目还未升级到TypeScript 4.9,可以用泛型函数来实现类型约束和字面量保留:

interface StoreCatalog {
  products: { name: string }[];
}

// 泛型函数确保传入的配置符合StoreCatalog类型
function createStoreCatalog<T extends StoreCatalog>(config: T) {
  return config as const;
}

const groceryStoreConfig = createStoreCatalog({
  products: [{ name: "apples" }, { name: "bananas" }],
});

// 正确得到类型:"apples" | "bananas"
export type GroceryStoreProductNames = (typeof groceryStoreConfig)["products"][number]["name"];

// 添加额外属性会触发类型错误
const invalidConfig = createStoreCatalog({
  products: [{ name: "apples", extra: "oops" }],
});
// 错误提示:类型 '{ name: string; extra: string; }' 不能赋值给类型 '{ name: string; }'

原因说明

直接给变量添加StoreCatalog类型标注时,TypeScript会将变量的类型拓宽到StoreCatalog,忽略as const带来的字面量窄化效果,因此products中的name会被视为宽泛的string类型。而satisfies或泛型函数的方式,既保证了对象结构符合StoreCatalog的要求,又保留了as const带来的字面量类型信息,从而能正确提取出具体的产品名称联合类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 09:05:24