【问题标题】:How to represent variable JSON data using TypeScript conditional types?如何使用 TypeScript 条件类型表示可变 JSON 数据?
【发布时间】:2019-09-08 23:15:20
【问题描述】:

我从后端获取 JSON 数据(我可以对其进行一些控制,因此如果有帮助,可以在某种程度上对其进行更改),如下所示:

{
  "attributes": [
    {
      "type": "string",
      "value": "foobar"
    },
    { 
      "type": "number",
      "value": 1234
    },
    {
      "type": "annotated_string",
      "value": {
        "value": "barfoo",
        "comment": "This is a comment"
      }
    }
  ]
}

我想找到一个可以代表这个的 TypeScript 类型。我阅读了有关条件类型的信息,它们似乎与问题的一部分相匹配。 value 取决于 type 字段的类型(实际上是值)。

我想出了这个:

type AttributeGroup = {
  attributes: Attribute[] // <-- This requires a generic parameter
}

enum AttributeType { "string" , "number", "annotated_string"}

type Attribute<T extends AttributeType> = {
  type: T;
  value: ExtractMyParameter<T>;
}

type AnnotatedString = {
  value: string;
  comment: string;
}

type ExtractMyParameter<T> =
  T extends AttributeType.number ? number :
  T extends AttributeType.string ? string :
  T extends AttributeType.annotated_string ? AnnotatedString :
    never;

let attr: Attribute<AttributeType.string> = { // <-- Ugly to have to define it twice
  type: AttributeType.string, // <-- I don't want to do this but instead: type: "string"
  value: "1234"
}

Try in Typescript Playground

有没有一种好方法可以将我的数据表示为 TypeScript 中的类型? 上面的代码由于各种原因不起作用:

  • Attribute[] 缺少类型参数,但数组的每个元素可能具有不同的类型。我想这可能会以某种方式通过 Union 类型解决?
  • 显式创建实例时必须专门定义 Attribute 很丑(这只是为了测试,所以还不错)

我认为必须有更好的方法来处理此类数据。

【问题讨论】:

  • TypeScript 完成的输入纯粹是编译时的事情。类型不能根据直到运行时才会出现的值而改变。
  • 你可能想使用quicktype.io - 他们有一个很棒的 JSON 到我使用的 Typescript 类型生成器!

标签: typescript typescript-generics


【解决方案1】:

值得注意的是,除非您正在创建这些属性值(您很可能是这样),否则键入并没有严格的帮助;否则你可能会陷入一种虚假的安全感!

您应该能够使用映射类型来实现您的用例(在这种情况下,这只是编写普通联合的快捷方式:TS Playground


type AttributeType = 'string'|'number'|'custom';

type Attribute<T extends AttributeType|unknown = unknown> = T extends AttributeType ? {
  'string': {type: T, value: string};
  'number': {type: T, value: number};
  'custom': {};
}[T] : {type: unknown, value: unknown};

let attr: Attribute<'string'> = {
  type: 'string',
  value: "1234",
}

let badValue: Attribute<'number'> = {
  type: 'number',
  // Type 'string' is not assignable to type 'number'.
  value: "1234",
}

let badType: Attribute<'string'> = {
  // Type '"number"' is not assignable to type '"string"'.
  type: 'number',
  value: "1234",
}

我还通过添加默认的unknown 类型使 Attribute[] 起作用。

【讨论】:

  • 谢谢。要从 JSON 转到这个,我会使用自定义反序列化器,通过自省 JSON 数据来实例化正确的类型?
猜你喜欢
  • 2021-12-12
  • 2019-02-10
  • 1970-01-01
  • 2023-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-23
  • 1970-01-01
相关资源
最近更新 更多