【问题标题】:Widen a type with a type generic in Typescript在 Typescript 中使用泛型类型扩展类型
【发布时间】:2025-12-17 01:15:01
【问题描述】:

在某些情况下,我想扩大按字面转换的对象的类型(使用“as const”),因此它的属性将被推断为字符串或数字,而不是字面意义上的。

假设我有以下类型

const obj = [
   {
      type:"student", 
      name:"Yossi"
   }, 
   {
      type: "Teacher", 
      name: "Lili"
   }
] as const

type Person = typeof obj [number]

我希望从字面上推断 obj 的类型,但 Person 要更宽,所以它的类型和名称是字符串。是否有一个泛型可以允许以下内容:

type Person = Widen<typeof obj [number]>

【问题讨论】:

  • 不太可能。用例是什么?实际上,每个属性只有两个可能的值。 TypeScript 可以正确推断窄类型。
  • @MadaraUchiha,我希望有一个组件(函数)可以接受并专门处理学生和老师,因此只能接受 obj 的值,以及另一个更广泛的组件/函数,并且可以接受任何人,无论他的职业是什么。
  • 有人介意我在这里将“加宽”编辑为“加宽”吗?
  • @jcalz,我修好了。无论如何,我不是以英语为母语的人,所以如有必要,请随时纠正或建议。

标签: typescript


【解决方案1】:

有趣的案例。我们可以尝试通过映射类型来创建这样的实用程序。考虑:

// it transforms our specific types into primitive origins
type ToPrimitive<T> =
  T extends string ? string
  : T extends number ? number
  : T extends boolean ? boolean
  : T;
// mapped types which will preserve keys with more wide value types
type Widen<O> = {
  [K in keyof O]: ToPrimitive<O[K]>
}
// using
type Person = Widen<typeof obj[number]>
const a: Person = {
  name: 'name', // string
  type: 'type' // string
}

我们可以扩展ToPrimitive,通过添加额外的条件来考虑对象、数组等其他类型。

我看到你的obj 元素类型或原始类型是一 - {name: string, type: string}。然后我们可以通过以下方式从第一个元素创建一个类型:

type Person = Widen<typeof obj[0]>;
// and this nicely evaluates to:
type Person = {
    readonly type: string;
    readonly name: string;
}

【讨论】:

  • > 我们可以扩展 ToPrimitive 以通过添加附加条件来考虑对象、数组等其他类型。这对于嵌套对象在实践中如何工作,同时保持类型安全?