我希望将特殊关键字的数组传递给一个类型,并基于这些关键字扩展该类型

type Keywords = 'totals' | 'body'  // ...and more

type Model<K extends Keywords[] = []> = {
  id: number
} 
& (K extends 'totals'[] ? {total: number, amount: number}: {})
& (K extends 'body'[] ? {body: string, name: string}: {})

const m: Model<['totals', 'body']> = {id: 1}   // Main problem here: Only id exist

我不知道怎么查K里面是不是'totals'.在上面的示例中,这两个条件都应该有效,因为'totals''body'被传递给泛型array.但看起来它们都是无效的.

次要问题(不是那么重要,但需要解决):

const words: Keywords[] = ['totals']  

我想确保words具有正确的类型,但它得到了所有可能的Keywords,而不仅仅是分配给它的.我们的目标是这样使用它:

type NewModel = Model<typeof words>

推荐答案

不判断K extends "totals"[],而是交换它并判断元素类型,而不是数组类型:"totals" extends K[number].有时很难考虑使用联合,但请记住,当您扩展一个联合时,您将使联合的成员数量增加reduce"totals""totals" | "body"的子类型,但"totals" | "body"不是"totals"的子类型.

如果你做到了这两件事,它就会奏效:

type Keywords = "totals" | "body"; // ...and more

type Model<K extends Keywords[] = []> = {
    id: number;
}
& ("totals" extends K[number] ? { total: number; amount: number } : {})
& ("body" extends K[number] ? { body: string; name: string } : {});

const m: Model<["totals", "body"]> = { id: 1 }; // Missing properties error as desired

Playground link

次要问题(不是那么重要,但需要解决):

const words: Keywords[] = ['totals']  

在那里,words的类型是just,Keywords[],而不是具体的"totals"[],所以它太开放了.你可以使用"totals"[],但这是多余的,理想情况下,我们想让TypeScrip为我们推断出该类型.要做到这一点,我们有两个 Select :as const或更新的satisfies(感谢您提醒我):

const words = ["totals"] as const;
// or
const words = ["totals"] satisfies Keywords[];

两者的结果都是words的类型为"totals"[],但是satisfies给了我们更好的开发体验,如果我们在数组中包括不在Keyword中的元素,它会警告我们,所以这可能就是我们想要的.

由于这会创建只读类型,因此需要将类型参数约束从Model更新为K extends readonly Keywords[]:

type Keywords = "totals" | "body"; // ...and more

type Model<K extends readonly Keywords[] = []> = {
// −−−−−−−−−−−−−−−−−−^^^^^^^^
    id: number;
}
& ("totals" extends K[number] ? { total: number; amount: number } : {})
& ("body" extends K[number] ? { body: string; name: string } : {});

const words = ["totals"] satisfies Keywords[];
//         ^             ^^^^^^^^^^^^^^^^^^^^

const m2: Model<typeof words> = { id: 1 }; // Missing properties error as desired

Playground link

Typescript相关问答推荐

如何根据参数的值缩小函数内的签名范围?

Typescript:将内部函数参数推断为子对象键的类型

如何基于对象关键字派生类型?

使用前的组件渲染状态更新

对深度对象键/路径进行适当的智能感知和类型判断,作为函数参数,而不会触发递归类型限制器

如何通过TypeScript中的工厂函数将区分的联合映射到具体的类型(如类)?

如何在TypeScrip中正确键入元素和事件目标?

在对象中将缺省值设置为空值

TypeScrip:来自先前参数的参数中的计算(computed)属性名称

Angular文件上传到Spring Boot失败,多部分边界拒绝

寻址对象中路径的泛型类型

将具有Readonly数组属性的对象接口转换为数组

如何正确调用创建的类型?

17个Angular 的延迟观察.如何在模板中转义@符号?

基于泛型的类型脚本修改类型

如何使对象同时具有隐式和显式类型

是否可以使用元组中对象的键来映射类型

递归类型名称

通用可选函数参数返回类型

如何使用 TypeScript 接口中第一个属性的值定义第二个属性