有没有办法将类型声明中特定键的值用作同一声明中另一个键的类型(在 Typescript 中)?

Posted

技术标签:

【中文标题】有没有办法将类型声明中特定键的值用作同一声明中另一个键的类型(在 Typescript 中)?【英文标题】:Is there a way to use the value from a specific key in a type declaration as the type of another key in that same declaration (in Typescript)? 【发布时间】:2021-06-15 05:51:34 【问题描述】:

假设我正在尝试创建一个变量类型,它采用 type 键,该键的类型为 string:有没有办法从键名为 type 并将其用作该类型声明中另一个键的类型? (不使用泛型)

例如,

type Variable = 
  name: string;
  required: boolean;
  type: string;
  defaultValue: Variable["type"];


const newWorkingVar: Variable = 
  name: "count",
  required: true,
  type: "number",
  defaultValue: 22 // This should work


const newErrorVar: Variable = 
  name: "count",
  required: true,
  type: "number",
  defaultValue: "test" // This should error

【问题讨论】:

你希望编译器如何理解字符串"number"number 类型有任何关系?我想你可以建立一个映射,然后建立一个像this 这样的联合,但我不知道这是否是你要找的。您能否在最后解释一下括号中的“不使用泛型”要求?这有点像说“我有一罐汤要打开(不使用这个开罐器)”。这可能是可能的,但如果你能解释为什么你的用例排除了开罐器,呃,泛型,你会更幸运。 用例是拥有一个简单的 JSON 对象,该对象也可以在具有类型安全性的 Typescript 中进行编辑。我需要在 JSON 对象中设置类型(并读取该值),而不仅仅是将其用于类型安全。但是你的例子有效!感谢您的回答,它更通用但不如@Linda Paste 简洁 @jcalz 如果您发布您的解决方案并附上解释,这将有助于我,我敢肯定,其他人! 【参考方案1】:

如果没有泛型,您将需要合并所有有效的 typedefaultValue 配对。

type Pair = 
  |  type: "number", defaultValue: number 
  |  type: "string", defaultValue: string 
  |  type: "user", defaultValue: User 

type Variable = 
  name: string;
  required: boolean;
 & Pair;

这将在type: "number", defaultValue: "test" 上得到你想要的错误,因为它不能分配给Pair 联合的任何成员。

键入'名称:字符串;要求:真;类型:“数字”;默认值:字符串; ' 不可分配给类型 'Variable'。

属性“defaultValue”的类型不兼容。

类型“字符串”不能分配给类型“数字”

不幸的是,没有办法(据我所知)将类型与其字符串名称相关联,因此您需要手动构建 Pair 联合。

Typescript Playground Link

【讨论】:

【参考方案2】:

这个答案类似于@LindaPaiste 的答案,只是从名称到类型的映射保留在一个单独的类型中,然后对其进行操作以产生Variable。例如,您的映射可能如下所示:

type TypeMapping = 
  number: number;
  string: string;
  boolean: boolean
  // add more here as needed

然后Variable 可能是

type Variable =  [K in keyof TypeMapping]: 
  name: string;
  required: boolean;
  type: K;
  defaultValue: TypeMapping[K];
 [keyof TypeMapping]

这可以通过从TypeMapping 获取每个键K 并将属性类型从TypeMapping[K] 转换为Variable 的子类型K(其中type 是键,defaultValue 是属性类型)。生成的mapped type 并不是我们想要的,因为它仍然具有与TypeMapping 相同的键。我们通过indexing into it 得到其属性的并集。

结果:

/* type Variable = 
    name: string;
    required: boolean;
    type: "string";
    defaultValue: string;
 | 
    name: string;
    required: boolean;
    type: "number";
    defaultValue: number;
 | 
    name: string;
    required: boolean;
    type: "boolean";
    defaultValue: boolean;
 */

现在你得到了你正在寻找的行为:

const newWorkingVar: Variable = 
  name: "count",
  required: true,
  type: "number",
  defaultValue: 22 // okay


const newErrorVar: Variable = 
  name: "count",
  required: true,
  type: "number",
  defaultValue: "test" // error!

Playground link to code

【讨论】:

以上是关于有没有办法将类型声明中特定键的值用作同一声明中另一个键的类型(在 Typescript 中)?的主要内容,如果未能解决你的问题,请参考以下文章

在具有 C++ 中另一个类型的类中声明属性 [重复]

如何将表中的数据用作 SQL 中另一个命令的值?

在 C# 中:如何声明一个类型为键的通用字典,该类型的 IEnumerable<> 作为值?

调用C++类中另一个头文件中定义的函数[重复]

PhpStorm - 有没有办法将 PHPDoc 转换为类型提示并返回类型声明?

SQLite。按特定顺序更新主键的值