简体   繁体   English

有没有办法将类型声明中特定键的值用作同一声明中另一个键的类型(在 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)?

Let's say I'm trying to create a Variable type that takes a type key which has a type of string : is there a way to access the value from the key called type and use that as the type for another key in that type declaration?假设我正在尝试创建一个变量类型,该类型采用具有字符串类型的类型键:有没有办法从名为type的键访问值并将其用作该类型声明中另一个键的类型? (Without using Generic Types) (不使用泛型类型)

For example,例如,

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
}

Without generics you would need to have a union of all valid pairings of type and defaultValue .如果没有 generics ,您需要将typedefaultValue的所有有效配对联合起来。

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

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

This will get you the error that you want on {type: "number", defaultValue: "test"} as that is not assignable to any member of the Pair union.这将在{type: "number", defaultValue: "test"}上得到你想要的错误,因为它不能分配给Pair union 的任何成员。

Type '{ name: string;键入'{名称:字符串; required: true;要求:真; type: "number";类型:“数字”; defaultValue: string;默认值:字符串; }' is not assignable to type 'Variable'. }' 不可分配给类型“变量”。

Types of property 'defaultValue' are incompatible.属性“defaultValue”的类型不兼容。

Type 'string' is not assignable to type 'number'类型“字符串”不可分配给类型“数字”

Unfortunately there is not a way (that I know of) to associate types with their string names, so you need to build the Pair union manually.不幸的是,没有办法(据我所知)将类型与其字符串名称相关联,因此您需要手动构建Pair联合。

Typescript Playground Link Typescript 游乐场链接

This answer is similar to @LindaPaiste's, with the minor change that the mapping from names to types is kept in a separate type, which is then manipulated to produce Variable .这个答案类似于@LindaPaiste 的答案,只是从名称到类型的映射保留在一个单独的类型中,然后对其进行操作以生成Variable For example, your mapping could look like this:例如,您的映射可能如下所示:

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

And then Variable could be然后Variable可以是

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

This works by taking each key K from TypeMapping and transforming the property type from TypeMapping[K] to the subtype of Variable for that K (where type is the key and defaultValue is the property type).这通过从TypeMapping中获取每个键K并将属性类型从TypeMapping[K]转换为该KVariable的子类型(其中type是键, defaultValue是属性类型)来工作。 The resulting mapped type is not exactly what we want because it still has the same keys as TypeMapping .生成的映射类型并不完全是我们想要的,因为它仍然具有与TypeMapping相同的键。 We get the union of its properties by indexing into it .我们通过索引它来获得它的属性的并集。

Result:结果:

/* 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;
} */

And now you get the behavior you're looking for:现在你得到了你正在寻找的行为:

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 Playground 代码链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM