使用动态/计算键选择<S, K> 类型
Posted
技术标签:
【中文标题】使用动态/计算键选择<S, K> 类型【英文标题】:Pick<S, K> type with dynamic/computed keys 【发布时间】:2017-06-24 17:13:02 【问题描述】:最新的@types/react
(v15.0.6
) 利用TypeScript 2.1 中为setState
添加的功能,即Pick<S, K>
。这是一件好事,因为现在打字是正确的,因为在更新之前打字“不知道”setState
正在合并 this.state
,而不是替换它。
此外,使用Pick
使setState
函数在允许输入方面非常严格。无法再向 state
添加未在组件定义中定义的属性(React.Component
的第二个泛型。
但定义动态更新处理程序也比较困难。例如:
import * as React from 'react';
interface Person
name: string;
age: number|undefined;
export default class PersonComponent extends React.Component<void, Person>
constructor(props:any)
super(props);
this.state =
name: '',
age: undefined
;
this.handleUpdate = this.handleUpdate.bind(this);
handleUpdate (e:React.SyntheticEvent<htmlInputElement>)
const key = e.currentTarget.name as keyof Person;
const value = e.currentTarget.value;
this.setState( [key]: value );
render()
return (
<form>
<input type="text" name="name" value=this.state.name onChange=this.handleUpdate />
<input type="text" name="age" value=this.state.age onChange=this.handleUpdate />
</form>
);
setState
函数会抛出以下错误
[ts] Argument of type ' [x: string]: string; ' is not assignable
to parameter of type 'Pick<Person, "name" | "age">'.
Property 'name' is missing in type ' [x: string]: string; '.
即使key
的类型是"name" | "age"
。
除了有一个单独的updateName
和updateAge
函数之外,我找不到解决方案。有谁知道如何将Pick
与动态键值一起使用?
【问题讨论】:
【参考方案1】:我认为这可能会解决您的问题。
type State =
name: string,
age: number | undefined
;
type StateKeys = keyof State;
dynSetState(key: StateKeys, value: string)
this.setState(
[key]: value
as Pick<State, keyof State>)
如果值不在可能的属性值类型集合中,这仍然会适当地给出错误,但如果键不在可能的属性键集合中,则不会给出错误。
参考:https://github.com/DefinitelyTyped/DefinitelyTyped/issues/26635
【讨论】:
【参考方案2】:塞巴斯蒂安的答案不再对我有用(尽管在某个阶段它确实有效)。我现在执行以下操作,直到它在 Typescript 核心中得到解决(根据 Sebastians 回答中列出的问题):
handleUpdate (e:React.SyntheticEvent<HTMLInputElement>)
const newState = ;
newState[e.currentTarget.name] = e.currentTarget.value;
this.setState(newState);
虽然很烂,但是很管用
【讨论】:
【参考方案3】:因此,在进行更多研究后,我可以提供更多关于上述代码中发生的情况的背景信息。
当您执行const name = 'Bob'
之类的操作时,变量name
的类型是'Bob'
不是 字符串。但是,如果将const
替换为let
(let name = 'Bob'
),则变量name
的类型将是string
。
这个概念被称为“加宽”。基本上,这意味着类型系统试图尽可能明确。因为const
不能重新赋值 TypeScript 可以推断出确切的类型。 let
语句可以重新分配。因此,TypeScript 将推断string
(在上面的示例中)作为name
的类型。
const key = e.currentTarget.name as keyof Person
也是如此。 key
将是(联合)类型"name"|"age"
,这正是我们想要的。 但是在表达式this.setState( [key]: value );
变量key
被(不正确地)扩大到string
。
tl;dr; 似乎 TypeScript 中存在错误。我将问题发布到 Github 存储库和 TypeScript 团队 is investigating the problem。 :)
作为临时解决方法,您可以这样做:
this.setState( [key as any]: value );
【讨论】:
感谢您的精彩解释。对于这种情况,此问题是否已修复或任何其他解决方法?以上是关于使用动态/计算键选择<S, K> 类型的主要内容,如果未能解决你的问题,请参考以下文章
为啥新的 `Pick<T, K extends keyof T>` 类型允许在 React 的 `setState()` 中使用 `K` 的子集?