在基于超类型的对象创建子类型的对象时,如何确保仅手动提供缺少的属性?

时间:2019-06-06 15:19:33

标签: typescript

我从api(int main() { int width = 512; int height = 512; std::ofstream ofs("plot.ppm", std::ios::out); ofs << "P3\n" << width << " " << height << "\n255\n"; for (int h = 0;h< height;h++) { for (int w = 0; w < width; w++) { vec3f col; float x = ((float)w - 256); float y = -((float)h - 256); if (h == 256||w==256)col = vec3f(0, 0, 0);//axes else col = vec3f(1,1,1);//background if (y==x)col = vec3f(0, 0, 0);//straight line if ((y*y) == (4*16*x))col=vec3f(1, 0, 0);//parabola int r = int(255.99 * col.x); int g = int(255.99 * col.y); int b = int(255.99 * col.z); ofs << r << " " << g << " " << b << "\n"; } } ofs.close(); } )获得带有用户详细信息的json。该api还提供了响应的类型(plot.ppm,当api更新其响应结构时,该接口会自动导入我的代码库中。

我从api中读取了json并添加了其他有用的属性,从而创建了readUserFromApi。创建interface User时,我只想提供 api没有提供的属性。将来,如果api还将为用户提供detailedUser,则我代码中的detailedUser将自动更新,并且我想输入一个打字错误,告诉我不需要手动提供{{ 1}}在构建name时,因为interface User已经来自api。

我有一个解决方案,请参见name,但应该有一个更优雅的解决方案...

code

detailedUser

1 个答案:

答案 0 :(得分:0)

对于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
})