typescript - 在基于超类型对象创建子类型对象时,如何确保我仅手动提供缺少的属性?
问题描述
我从 api ( ) 获得了一个包含用户详细信息的 json readUserFromApi
。该 api 还提供了其响应的类型 ( interface User
),并且当/如果 api 更新其响应结构时,此接口会自动导入到我的代码库中。
我从 api 读取 json 并添加其他有用的属性,创建detailedUser
. 创建时detailedUser
我只想提供api 未提供的属性。将来,如果api 也将为name
用户提供,我interface User
的代码中的name
detailedUser
name
我有一个解决方案,请参阅dummyVar
,但应该有一个更优雅的解决方案......
(代码)
type Common<A, B> = {
[P in keyof A & keyof B]: A[P] | B[P];
}
type Exactly<T, U extends T> = T & Record<Exclude<keyof U, keyof T>, never>
interface User {
id: number
}
interface DetailedUser {
id: number
name: string
sex: string
}
const readUserFromApi = () => ({id: 1})
const user: User = readUserFromApi()
const detailedUser: DetailedUser = {
// I want an error if by mistake I provide a default value for `id`,
// I dont have to do that, `id` comes from `user`
name: 'default name',
sex: 'f',
...user
}
// when interface User changes in the future and get a new property `name`,
// line below will trigger a typescript error - as I expect
declare const dummyVar: Exactly<Common<typeof user, {name: any, sex: any}>, {}>
解决方案
对于DetailedUser
类型,如果我们使用类型别名而不是接口,我们可以直接在类型中得到错误。对于像这种对象类型这样的简单类型,应该没有实际的区别。
interface User {
id: number
//name: string // comment this and you get an error below
}
type SafeExtend<TBase, TExt extends Record<Extract<keyof TBase, keyof TExt>, never>> = TBase & TExt
type DetailedUser = SafeExtend<User, {
name: string
sex: string
}>
SafeExtend
将采用基本接口 ( User
) 和包含您要添加的任何额外字段的类型。如果添加的字段已经在基本界面中,您将收到错误消息。
对于第二部分,如果您指定字段,您希望在传播中出现错误,我认为使用传播是不可能的。如果您改用函数,则可以这样做:
function safeSpread<TBase, TExt>(base: TBase, ext: TExt & Record<Extract<keyof TBase, keyof TExt>, never> ) {
return {
...base,
...ext
};
}
const detailedUser: DetailedUser = safeSpread(user, {
name: 'default name',
sex: 'f',
id: 0 // error
})
推荐阅读
- reactjs - 如何更改TextField中所选文本的字体大小 从material-ui中选择
- c# - 清理无效的 xml 字符串,使其有效 xml
- html - 在 flexbox 中缩放 SVG(方向行)
- c++ - 在进行socket编程时如何多次发送和接收数据?
- react-native - React Native - 递归 setTimeout 重复运行某些东西
- node.js - 如何在 node.js 中读取文件
- django - 无法在 Docker 上将 Postgres 容器与 Django 容器连接起来
- react-native - AXIOS 传入请求标头在 React Native 中转换为小写
- java - 如何在 MOXy 中使用实例化的 XmlAdapter?
- python - 有没有办法两次使用随机链接?即像维基百科随机文章生成器,但用于不同的站点