在 Typescript 中将键值映射转换为具有必填字段(或失败)的类型

问题描述 投票:0回答:1

我有两种兴趣,一个收藏:

type One = {
    'type': 'One';
    a: string;
    x?: string;
}

type Two = {
    'type': 'Two';
    b: string;
    y?: string;
}

const collection: Map<string, string>[];

我希望集合包含的元素是键值映射,匹配一种或两种类型的结构;我也无法提前确定这一点(某些元素可能既不匹配也没有额外的键)。重要的是,最常见的错误情况是元素缺少必填字段之一:

[ { 'type': 'One',
    'a': 'value',
    'x': 'another',
  },
  { 'type': 'Two',
    'b': 'value',
  },
  { 'type': 'One'
  }, // this element should error when the function is called
]

所以不允许在类型上再多约束一些。但是,我想通过尽可能构造每个选项或抛出错误来编写像

typeCastOrError(m: Map<keyof One | keyof Two,string>): One | Two
这样的函数。

但是我不清楚如何做到这一点。我可能会构造类型并遍历它的键,但我不能将它构造为空,因为键是必需的。我正在使用最严格的 tsconfig 类型检查。

如何安全地将类型转换为具有所需类型的值?

typescript typescript-generics type-safety
1个回答
0
投票

我的建议是使用 Zod 来定义类型一和二,这为您提供了运行时验证器的副产品。那么得到一个配套的物品就是小事了

这是一个你可以在 this repl...

看到并运行的工作示例
import { z } from "zod";

const ONE_SCHEMA = z.object({
  type: z.literal("One"),
  a: z.string(),
  x: z.string().optional()
})
type One = z.infer<typeof ONE_SCHEMA>

const TWO_SCHEMA = z.object({
  type: z.literal("Two"),
  b: z.string(),
  y: z.string().optional()
})
type Two = z.infer<typeof TWO_SCHEMA>

function validate(map: Map<string, string>): One | Two | null {
  try {
    const obj = Object.fromEntries(map.entries());
    return z.union([
      ONE_SCHEMA,
      TWO_SCHEMA
    ]).parse(obj);
  }
  catch (error) {
    return null
  }
}

function validateAndPrint(map: Map<string, string>) {
  console.log(validate(map))
}

validateAndPrint(new Map([
  ["type", "One"],
  ["a", "value"],
  ["x", "another"],
]))

validateAndPrint(new Map([
  ["type", "Two"],
  ["b", "value"],
]))

validateAndPrint(new Map([
  ["type", "One"],
]))
© www.soinside.com 2019 - 2024. All rights reserved.