我有两种兴趣,一个收藏:
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 类型检查。
如何安全地将类型转换为具有所需类型的值?
我的建议是使用 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"],
]))