如何定义含已有对象属性值类型的TypeScript接口?
解决方案:让接口属性对应已有对象的任意属性值
这个问题的核心是TypeScript的类型拓宽行为——默认情况下,你定义的fruits对象属性会被推断为宽泛的string类型,而不是你手动定义的Fruits字面量联合类型,所以才会出现“string不能赋值给Fruits”的错误。咱们一步步解决它:
最优方案:用as const断言+类型推导
我们可以让TypeScript自动从fruits对象派生类型,不用手动维护Fruits联合类型,这样既避免重复代码,又能保证类型和对象值完全同步:
// 用as const断言,让TypeScript把属性值保留为字面量类型,不拓宽为string const fruits = { APPLE: 'APPLE', BANANA: 'BANANA', ORANGE: 'ORANGE' } as const; // 从fruits对象自动推导联合类型 type Fruits = typeof fruits[keyof typeof fruits]; interface IGroceries { fruit: Fruits, vegetables: string[] } const initialGroceriesState: IGroceries = { fruit: fruits.APPLE, // 现在类型匹配,不会报错 vegetables: [] }
为什么这能解决问题?
as const告诉TypeScript:这个对象的属性是只读的字面量值,不能被修改,因此不会把属性类型拓宽为string,而是保留具体的'APPLE'、'BANANA'等值类型。typeof fruits[keyof typeof fruits]是TypeScript的类型查询语法:typeof fruits获取到fruits对象的类型keyof typeof fruits获取到对象所有键的联合类型('APPLE' | 'BANANA' | 'ORANGE')- 最后用索引访问得到所有键对应的值的联合类型,也就是我们需要的
Fruits类型。
备选方案:给对象指定明确类型
如果你更倾向于手动定义Fruits类型,也可以给fruits对象指定类型,强制它的属性值和Fruits类型匹配:
type Fruits = 'APPLE' | 'BANANA' | 'ORANGE'; // 给fruits指定类型为Record<Fruits, Fruits>,确保属性值是对应的字面量 const fruits: Record<Fruits, Fruits> = { APPLE: 'APPLE', BANANA: 'BANANA', ORANGE: 'ORANGE' }; interface IGroceries { fruit: Fruits, vegetables: string[] } const initialGroceriesState: IGroceries = { fruit: fruits.APPLE, // 类型匹配 vegetables: [] }
这种方式需要手动维护Fruits类型和fruits对象的一致性,当你新增或修改fruits的属性时,需要同步更新Fruits类型,不如第一种方案灵活。
内容的提问来源于stack exchange,提问作者Jon Lamb
相关产品推荐
相关产品推荐

