typescript - (打字稿)您能否验证部分返回类型中的所有可能属性在编译时是否可以选择性地映射到新对象上?
问题描述
大家好——我有一个由数据库读取器组成的服务,中间有一些转换,以及一个将请求发布到第三方 API 的“同步”服务。
类型如下所示:
export interface RowType {
userId: string,
userSeq: number,
info: InfoType
}
export type InfoType = Partial<{
propertyA: number,
propertyB: boolean,
propertyC: string,
propertyD: boolean,
}>;
阅读器看起来像:
export const usePostgresReader = (
pool: Pool,
tenant: string,
limit = 1000,
): PersistedReader<RowType> => ({
head: async () =>
pool
.query(
`SELECT COALESCE(MAX(position), 0) as head
FROM table_name`,
)
.then(({ rows }) => Number(rows[0].head)),
read: async from =>
pool
.query(
`SELECT position, user_id, user_seq, payload
FROM table_name
WHERE tenant = $1 AND position > $2
ORDER BY position ASC
LIMIT $3`,
[tenant, from, limit],
)
.then(({ rows }) =>
rows.map<Persisted<RowType>>(
({ position, user_id: userId, user_seq: userSeq, payload }) => ({
position: Number(position),
payload: {
customerId,
customerSequence: Number(customerSequence),
info: {
propertyA: info.propertyA,
propertyB: info.propertyB,
propertyC: info.propertyC
// should be propertyD: info.propertyD, but the dev forgets to add it
},
},
}),
),
),
});
“同步”服务如下所示:
export const useSyncService = (
getToken: AuthService,
): SyncService => async rows =>
fetch(`https://some-other-site.com/api`, {
method: `POST`,
headers: {
Authorization: `Bearer ${await getToken()}`,
'Content-Type': `application/json`,
},
timeout: 60000,
body: JSON.stringify({
input: rows.map(({ userId, info }) => ({
apiThingA: info.propertyA,
apiThingB: info.propertyB,
apiThingC: info.propertyC,
apiThingD: info.propertyD // compiler is happy with this because of partial type
})),
}),
})
处理此代码的工程师不断向同步负载添加新字段,我们现在偶然发现了几次 - 我们将新字段添加到请求的正文中,而不是添加到读取器返回类型。
但是,因为行类型是部分的(并且必须是,因为许多服务使用不同的有效负载填充它正在读取的所有表),编译器不会抱怨从允许的类型映射的值是未定义,即使您忘记将其添加到阅读器,它也将始终未定义。
有没有办法在编译时捕捉到这个?我试图弄清楚如何使用像 Zod ( https://github.com/colinhacks/zod ) 这样的库来验证这些东西,但我目前的解决方案只会在运行时捕获它。
提前干杯,传奇!
解决方案
我想出的编译时解决方案是将部分类型重新声明为联合类型。
IE。代替:
export type InfoType = Partial<{...}>
...我明确声明了所有可能的有效载荷形状,并将其声明InfoType
为所有这些形状的联合。
如:
type InfoTypeA = {...}
type InfoTypeB = {...}
type InfoTypeC = {...}
type InfoTypeD = {...}
export type InfoType = InfoTypeA | InfoTypeB | InfoTypeC | InfoTypeD
这样,请求正文 ( {}
) 将不再有效,因此如果编译器发现无法将可用值映射到联合的有效子类型的情况,则会引发类型错误。
希望这可以帮助遇到类似问题的其他人!
推荐阅读
- c++ - 可变参数模板模板的完美转发
- php - 如何更新字段以将值推送到 Laravel 中的现有值
- ios - 结合两个文本字段验证功能
- javascript - 基于此现有数组对象创建新的多维数组
- shell - 休眠调试指令 UNIX Shell 脚本
- javascript - React Native Flatlist 在数据更新时多次渲染同一个项目
- lua - 为什么在远程事件中运行此函数时出现“无法将值转换为对象”?
- php - 我遇到内部服务器错误
- c# - 在 Java 中是否有与 @FindAll 等效的 C#
- google-drive-api - 当我将驱动器链接作为媒体 url 提供时,它不起作用,但 amazon s3 可以正常工作吗?