示例代码:

enum ENUM_A { 
  ONE="ONE",
  TWO="TWO",
  THREE="THREE",
  FOUR="FOUR"
}

interface TYPE_A {
  myArray: ENUM_A[],
  mySpecificMapping: {
    [key in ENUM_A]?: boolean
  }
}
const myObject: TYPE_A = {
  myArray: [ENUM_A.ONE, ENUM_A.THREE],
  mySpecificMapping: {
    [ENUM_A.ONE]: true,
    // Uncommenting the line below should result in a TypeScript error
    // [ENUM_A.TWO]: true,
    [ENUM_A.THREE]: true,
    // Uncommenting the line below should result in a TypeScript error
    // [ENUM_A.FOUR]: true,
  }
}

如果"mySpecificMapping"包含"myArray"中不存在的键,myBody应该出错

我想我需要在这里使用自引用类型?

推荐答案

是的,为了使其发挥作用,您需要TypeA成为实际存在于myArray中的EnumA个成员中的generic,如下所示:

interface TypeA<T extends EnumA> {
  myArray: T[],
  mySpecificMapping: {
    [K in T]?: boolean
  }
}

然后你couldannotation改成

const myObject: TypeA<EnumA.ONE | EnumA.THREE> = {
  myArray: [EnumA.ONE, EnumA.THREE],
  mySpecificMapping: {
    [EnumA.ONE]: true,
    [EnumA.THREE]: true
  }
}

如果您将[EnumA.TWO]: true添加到mySpecificMapping,就会给您一个错误. 但写出EnumA.ONE | EnumA.THREE类型的论点是乏味且多余的.如果TypScript可以为您推断该类型参数,那就太好了,但这是microsoft/TypeScript#32794处请求的缺失功能.

如果您想要通用类型参数推断,则需要创建一个通用function来搭配TypeA. 以下是一个用于此目的的助手函数:

const typeA = <T extends EnumA>(t: TypeA<T>) => t;

const myObject = typeA({
  myArray: [EnumA.ONE, EnumA.THREE],
  mySpecificMapping: {
    [EnumA.ONE]: true,
    [EnumA.THREE]: true,
  }
});

现在您会看到myObject被推断为类型TypeA<EnumA.ONE | EnumA.THREE>,而无需您自己写出来.写const myObject = typeA({⋯})而不是const myObject: TypeA = {⋯}所需的工作量和按键量大致相同,所以希望这是可以接受的.


无论如何,让我们确保您得到您要求的行为:

const myObject = typeA({
  myArray: [EnumA.ONE, EnumA.THREE],
  mySpecificMapping: {
    [EnumA.ONE]: true,    
    [EnumA.TWO]: true, // error! 
    [EnumA.THREE]: true,
  }
});

看起来不错当添加myArray中不存在的mySpecificMapping键时,您会出现错误.

Playground link to code

Typescript相关问答推荐

当两个参数具有相同的通用类型时,如果没有第一个参数,则递减约束默认会导致第二个参数的错误推断

如何声明循环数组类型?

如何使用TypScript限制允许对JavaScript值进行的操作集?

如何将http上下文附加到angular中翻译模块发送的请求

调用另一个函数的函数的Typescript类型,参数相同

如何为父类构造函数中的修饰属性赋值?

类型脚本`Return;`vs`Return unfined;`

学习Angular :无法读取未定义的属性(正在读取推送)

使用axios在ngOnInit中初始化列表

错误TS2403:后续变量声明必须具有相同的类型.变量';CRYPTO';的类型必须是';CRYPATO';,但这里的类型是';CRYPATO';

如何使所有可选字段在打印脚本中都是必填字段,但不能多或少?

如何编写在返回函数上分配了属性的类型安全泛型闭包

为什么我的函数arg得到类型为Never?

KeyOf关键字在特定示例中是如何工作的

对于VUE3,错误XX不存在于从不存在的类型上意味着什么?

VUE 3类型';字符串';不可分配给类型';参考<;字符串&>

是否可以将类型参数约束为不具有属性?

如何提取具有索引签名的类型中定义的键

如何使用 AWS CDK 扩展默认 ALB 控制器策略?

如何使用 runInInjectionContext 中的参数测试功能性路由防护