我有一个API控制器,它需要像这样的主体参数
insertUser(@Body() user: IUser) {}
但是问题是我可以发布一个对象,该对象包含的属性比IUser
定义的更多。
确保user
严格遵守类型或克隆它仅保留接口IUser`中定义的内容的最简单的最简单方法是什么?
答案 0 :(得分:1)
我的答案将与框架无关。您询问如何强制TS不允许传递具有附加字段的类型的值,这意味着我们要具有该类型的排他性行为,具有相同的属性或不允许这样做。
首先,这种行为在类型级别上是无益的,就像给定值包含我们需要具有的字段一样,其他字段对我们来说并不重要。另一件事是,即使我们可以执行类型的编译时间检查器,但是如果您的数据来自API,则您需要在运行时级别进行验证。
首先是类型级别的排他类型行为实现:
type IUser = {
name: string;
lastname: string;
}
// utility type to enforce exlusive type
type OnlyExistingFields<Champion, Pretendent> = {
[K in keyof Pretendent]: K extends keyof Champion ? Pretendent[K] : never
}
// example type with more fields
type IMoreUser = IUser & {
age: number;
}
// instance of correct type
const u1: IUser = {
lastname: '',
name: ''
}
// instance of type with more fields
const u2: IMoreUser = {
lastname: '',
name: '',
age: 12
}
// below type declaration of exlusive function
declare function insertUser<U extends OnlyExistingFields<IUser, U>>(user: U): void
// usage:
insertUser(u1) // ? correct type is the same
insertUser(u2) // ? error type has more fields
上面是完全类型级别检查,我们只能传递特定类型的参数,不允许使用该类型的任何超集。
正如我所说的,以上解决方案仅是类型级别,实际上,如果对象在运行时具有或不希望使用接口,则无法在类型级别强制实施,一切都只是假设。
也就是说,我们还需要运行时转换器才能删除所有不需要的字段。考虑这样的转换器:
// converts object with probably more fields to object with only wanted fields
function toIUser<T extends IUser>(a: T): IUser {
return {
name: a.name,
lastname: a.lastname
}
}
const u3 = toIUser(u2); // u3 is IUser and also in runtime has only IUser fields