来自 JSON 模式的 TypeScript 交集(非联合)类型
TypeScript Intersection (not Union) Type from JSON Schema
我正在跟进 :
我有以下架构:
const schemas = {
POST: {
$schema: 'https://json-schema.org/draft/2019-09/schema#',
$id: 'https://api.netbizup.com/v1/health/schema.json',
type: 'object',
properties: {
body: {
type: 'object',
properties: {
greeting: {
type: 'string',
},
},
additionalProperties: false,
},
},
required: ['body'],
} as const,
PUT: {
$schema: 'https://json-schema.org/draft/2019-09/schema#',
$id: 'https://api.netbizup.com/v1/health/schema.json',
type: 'object',
properties: {
body: {
type: 'object',
properties: {
modified: {
type: 'boolean',
},
},
required: ['modified'],
additionalProperties: false,
},
},
required: ['body'],
} as const,
};
我正在使用 json-schema-to-ts
包中的 FromSchema
来推断上面 const
对象的每个 body
属性的类型。
我需要实现的是 POST
和 PUT
主体的交集类型。上一个问题中提供的答案非常适合创建 TypeScript Union
。问题当然是当我尝试访问 body
的成员时出现错误,因为并非所有属性都始终存在于每个 body
.
上
我什至想知道 TypeScript 是否允许我们验证如果我们从“选择的”body
对象访问一个属性,那么它将不允许我们访问另一个。
我创建了一个 Playground 来说明我的问题。
附件
It seems as if FromSchema cannot handle a union of the schemas. You can get around this by turning the union into a tuple, converting each schema in the tuple with FromSchema, then converting it back to a union.
为此我们首先需要 post
我在这里将 TuplifyUnion
重命名为 UnionToTuple
。
然后让我们编写一个类型来转换我们希望转换的模式联合。
我们需要将这个并集转换为一个元组,然后分别转换每个模式,最后将生成的元组转回一个并集。
type FromAllSchemas<U> = ConvertAll<UnionToTuple<U>>[number];
这是用 UnionToTuple
和 [number]
完成的。
现在写ConvertAll
.
type ConvertAll<T, R extends ReadonlyArray<unknown> = []> =
T extends [infer First, ...infer Rest]
? ConvertAll<Rest, [...R, FromSchema<First>]>
: R;
首先我们将第一个元素和其余元素推断为一个元组。
然后我们使用 FromSchema 将第一个元素转换为类型,并将其放入结果中。然后我们再次“调用”ConvertAll
,这次使用其余元素和新结果。
最后,如果我们无法推断出第一个元素 T 为空,那么我们只 return 结果 R.
我正在跟进
我有以下架构:
const schemas = {
POST: {
$schema: 'https://json-schema.org/draft/2019-09/schema#',
$id: 'https://api.netbizup.com/v1/health/schema.json',
type: 'object',
properties: {
body: {
type: 'object',
properties: {
greeting: {
type: 'string',
},
},
additionalProperties: false,
},
},
required: ['body'],
} as const,
PUT: {
$schema: 'https://json-schema.org/draft/2019-09/schema#',
$id: 'https://api.netbizup.com/v1/health/schema.json',
type: 'object',
properties: {
body: {
type: 'object',
properties: {
modified: {
type: 'boolean',
},
},
required: ['modified'],
additionalProperties: false,
},
},
required: ['body'],
} as const,
};
我正在使用 json-schema-to-ts
包中的 FromSchema
来推断上面 const
对象的每个 body
属性的类型。
我需要实现的是 POST
和 PUT
主体的交集类型。上一个问题中提供的答案非常适合创建 TypeScript Union
。问题当然是当我尝试访问 body
的成员时出现错误,因为并非所有属性都始终存在于每个 body
.
我什至想知道 TypeScript 是否允许我们验证如果我们从“选择的”body
对象访问一个属性,那么它将不允许我们访问另一个。
我创建了一个 Playground 来说明我的问题。
附件
It seems as if FromSchema cannot handle a union of the schemas. You can get around this by turning the union into a tuple, converting each schema in the tuple with FromSchema, then converting it back to a union.
为此我们首先需要 post
我在这里将 TuplifyUnion
重命名为 UnionToTuple
。
然后让我们编写一个类型来转换我们希望转换的模式联合。
我们需要将这个并集转换为一个元组,然后分别转换每个模式,最后将生成的元组转回一个并集。
type FromAllSchemas<U> = ConvertAll<UnionToTuple<U>>[number];
这是用 UnionToTuple
和 [number]
完成的。
现在写ConvertAll
.
type ConvertAll<T, R extends ReadonlyArray<unknown> = []> =
T extends [infer First, ...infer Rest]
? ConvertAll<Rest, [...R, FromSchema<First>]>
: R;
首先我们将第一个元素和其余元素推断为一个元组。
然后我们使用 FromSchema 将第一个元素转换为类型,并将其放入结果中。然后我们再次“调用”ConvertAll
,这次使用其余元素和新结果。
最后,如果我们无法推断出第一个元素 T 为空,那么我们只 return 结果 R.