我想从客户端创建一个具有名称作为参数的用户,并在服务器上分配created
。因此,我使用Pick<User, "name">
。但是当我向该函数传递完整的User
对象时,Typescript不会抱怨:
interface User {
name: string;
created: Date;
}
const user: User = {
name: "Test User",
created: new Date()
};
const createUser = (user: Pick<User, "name">): User => ({
name: user.name,
created: new Date()
});
const newUser1 = createUser(user); // No error
const newUser2 = createUser({
name: "Another Test User",
created: new Date() // Error
});
沙盒:https://codesandbox.io/s/unruffled-wave-tewh8
我希望这两种情况都将引发错误,但是第一种情况不会引发错误。为什么?
答案 0 :(得分:1)
类型User
是Pick<User, "name">
的结构子类型。类型为Pick<User, "name">
的对象是具有类型name
的{{1}}属性的任何对象,并且string
对象符合该描述,因此传递User
,其中应该是User
。
后一种情况是错误的,因为存在object literals cannot have excess properties的特殊规则。尽管您的第二个示例同样具有类型安全性,但与第一个示例相比,它更可能是一个错误,因此即使没有将其作为对象文字传递时,Typescript也会发出警告,尽管它会默默地接受相同的值。
如果您特别希望此函数不能用类型Pick<User, "name">
的参数来调用,则可以使它的参数类型不是User
的子类型:
User
但是,请注意,这并不能绝对阻止您使用interface UninitialisedUser {
name: string;
created?: undefined;
}
const createUser = (user: UninitialisedUser): User => ({
name: user.name,
created: new Date()
});
const newUser = createUser(user); // error
对象调用该函数。您仍然可以编写User
,然后let temp: { name: string } = user;
不会是类型错误。真的没有办法解决,但至少很难无意间做到这一点。