【问题标题】:Why does Pick<T, K> not throw an error when T is passed?为什么在传递 T 时 Pick<T, K> 不会抛出错误?
【发布时间】:2020-02-09 16:13:52
【问题描述】:

我想从客户端创建一个名称作为参数的用户,并在服务器上分配created。因此我使用Pick&lt;User, "name"&gt;。但是 Typescript 并没有抱怨,当我将完整的 User 对象传递给该函数时:

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

我希望这两种情况都会引发错误,但第一种情况不会引发。为什么?

【问题讨论】:

标签: typescript


【解决方案1】:

类型UserPick&lt;User, "name"&gt; 的结构子类型。 Pick&lt;User, "name"&gt; 类型的对象是具有string 类型的name 属性的任何对象,并且User 对象符合该描述,因此传递User 是类型安全的,其中Pick&lt;User, "name"&gt;预计。

后一种情况是错误的,因为有一个特殊的规则object literals cannot have excess properties。尽管您的第二个示例与第一个示例一样是类型安全的,但它比第一个示例更有可能是错误的,因此 Typescript 会发出警告,尽管当它没有作为对象文字传递时,它会默默地接受相同的值。

如果您特别希望此函数不能使用 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;,然后createUser(temp) 不会是类型错误。确实没有办法解决这个问题,但至少很难偶然做到这一点。

Playground Link

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-13
    相关资源
    最近更新 更多