简体   繁体   English

为什么新的&#39;挑选 <T, K extends keyof T> `在React的`setState()`中输入&#39;K`的子集?

[英]Why does the new `Pick<T, K extends keyof T>` type allow subsets of `K` in React's `setState()`?

I thought I understood the purpose of the new TS 2.1 Pick type , but then I saw how it was being used in the React type definitions and I don't understand: 我以为我理解了新的TS 2.1 Pick类型的目的,但后来我看到它是如何在React类型定义中使用的 ,我不明白:

declare class Component<S> {
    setState<K extends keyof S>(state: Pick<S, K>, callback?: () => any): void;
    state: Readonly<S>;
}

Which allows you to do this: 这允许你这样做:

interface PersonProps {
  name: string;
  age: number;
}

class Person extends Component<{}, PersonProps> {
  test() {
    this.setState({ age: 123 });
  }
}

My confusion here is that keyof S is { name, age } but I call setState() with only age -- why doesn't it complain about the missing name ? 我的困惑在于, keyof S{ name, age }但是我只用age调用setState() - 为什么不抱怨丢失的name

My first thought is that because Pick is an index type, it simply doesn't require all the keys to exist. 我的第一个想法是因为Pick是一种索引类型,它根本不需要存在所有键。 Makes sense. 说得通。 But if I try to assign the type directly: 但是,如果我尝试直接分配类型:

const ageState: Pick<PersonProps, keyof PersonProps> = { age: 123 };

It does complain about the missing name key: 确实抱怨缺少name密钥:

Type '{ age: number; }' is not assignable to type 'Pick<PersonProps, "name" | "age">'.
  Property 'name' is missing in type '{ age: number; }'.

I don't understand this. 我不明白这一点。 It seems all I did was fill in S with the type that S is already assigned to, and it went from allowing a sub-set of keys to requiring all keys. 似乎我所做的就是用S已经分配的类型填充S ,并且它从允许一键到需要所有键。 This is a big difference. 这是一个很大的不同。 Here it is in the Playground . 这是在游乐场 Can anyone explain this behavior? 谁能解释这种行为?

Short answer: if you really want an explicit type, you can use Pick<PersonProps, "age"> , but it's easier use implicit types instead. 简短回答:如果你真的想要一个显式类型,你可以使用Pick<PersonProps, "age"> ,但更容易使用隐式类型。

Long answer: 答案很长:

The key point is that the K is a generic type variable which extends keyof T . 关键点在于K是一个泛型类型变量,它扩展 keyof T

The type keyof PersonProps is equal to the string union "name" | "age" keyof PersonProps的类型keyof PersonProps等于字符串union "name" | "age" "name" | "age" . "name" | "age" The type "age" can be said to extend the type "name" | "age" 类型"age"可以说是扩展类型"name" | "age" "name" | "age" . "name" | "age"

Recall the definition of Pick is: 回想一下Pick的定义是:

type Pick<T, K extends keyof T> = {
  [P in K]: T[P];
}

which means for every K , the object described by this type must have a property P of same type as the property K in T . 这意味着对于每个K ,此类型描述的对象必须具有与T的属性K相同类型的属性P Your example playground code was: 你的示例游乐场代码是:

const person: Pick<PersonProps, keyof PersonProps> = { age: 123 };

Unwrapping the generic type variables, we get: 展开泛型类型变量,我们得到:

  • Pick<T, K extends keyof T> , Pick<T, K extends keyof T>
  • Pick<PersonProps, "name" | "age"> Pick<PersonProps, "name" | "age"> , Pick<PersonProps, "name" | "age">
  • [P in "name" | "age"]: PersonProps[P] [P in "name" | "age"]: PersonProps[P] , and finally [P in "name" | "age"]: PersonProps[P] ,最后
  • {name: string, age: number} . {name: string, age: number}

This is, of course, incompatible with { age: 123 } . 当然,这与{ age: 123 }不相容。 If you instead say: 如果你改为说:

const person: Pick<PersonProps, "age"> = { age: 123 };

then, following the same logic, the type of person will properly be equivalent to {age: number} . 然后,按照相同的逻辑,类型person将适当地等同于{age: number}

Of course, TypeScript is calculating all of these types for you anyway—that's how you got the error. 当然,TypeScript无论如何都会为你计算所有这些类型 - 这就是你得到错误的方法。 Since TypeScript already knows the types {age: number} and Pick<PersonProps, "age"> are compatible, you might as well keep the type impicit: 由于TypeScript已经知道类型{age: number}Pick<PersonProps, "age">是兼容的,因此您可以保持类型impicit:

const person = { age: 123 };

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么 typescript 不能正确推断 T[K]<t extends person, k keyof t> 通用的?</t> - Why typescript does not properly infer T[K] with <T extends Person, K extends keyof T> generic? 挑选<s, k>使用动态/计算键键入</s,> - Pick<S, K> type with dynamic/computed keys TypeScript 和 React Native:使用 Pick<T, K> 避免使我的代码臃肿 - TypeScript & React Native: Using Pick<T, K> to avoid bloating my code 为什么React在重新渲染之前不比较Previous State和New State? 为何在调用setState时始终呈现? - Why React does't compare Previous State and New State before re rendering? Why it always render when setState is called? 为什么不反应更新 setState 中的样式? - Why doesn't react update the style in the setState? 为什么 setState() 不更新 React 上的渲染? - Why setState() doesn't update render on React? 具有setState的Onblur事件不允许React中子级的onClick - Onblur event with setState doesn't allow onClick of child in React TypeScript w/ React - 'string' 类型的参数不可分配给'keyof T' 类型的参数 - TypeScript w/ React - Argument of type 'string' is not assignable to parameter of type 'keyof T' 无法设置状态反应 - Can't setState React 在这个基本的 React 应用程序中,为什么自定义组件“TextInput”允许我输入内容,即使常规的“input”字段不允许? - In this basic react application, why does the custom component `TextInput` allow me to type stuff in even though the regular `input` field doesn't?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM