我有一个 API Controller ,它采用这样的主体参数
insertUser(@Body() user: IUser) {}
但是问题是我可以发布一个包含比 IUser
定义的更多属性的对象。
确保 user
严格遵守类型或克隆它仅保留接口(interface) IUser` 中定义的内容的最简单、最干净的方法是什么?
最佳答案
我的回答与框架无关。您询问如何强制 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
上面是完全类型级别检查,我们只能传递特定类型的参数,不允许传递该类型的任何超集。
正如我所说,上面的解决方案只是类型级别,实际上,如果对象在运行时有或不需要接口(interface),则无法在类型级别强制执行,一切都只是假设。
也就是说,我们还需要运行时转换器才能删除所有不需要的字段。考虑这样的转换器:
// 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
关于javascript - Typescript 拒绝不符合接口(interface)的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60606650/