最新@types/react
(v15.0.6
)使用TypeScript 2.1中为setState
添加的功能,即Pick<S, K>
。这是一件好事,因为现在的打字是正确的,因为在更新打字之前&#34;并不知道&#34; 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
与动态键值一起使用?
答案 0 :(得分:10)
因此,在做了更多研究之后,我可以提供一些关于上述代码中发生的事情的更多背景信息。
当您执行const name = 'Bob'
之类的操作时,变量name
的类型为'Bob'
而不是字符串。但是,如果您将const
替换为let
(let name = 'Bob'
),则变量name
将为string
类型。
这个概念被称为&#34;拓宽&#34;。基本上,这意味着类型系统试图尽可能明确。由于无法重新分配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 repo和TypeScript团队is investigating the problem。 :)
作为临时解决方法,您可以:
this.setState({ [key as any]: value });
答案 1 :(得分:2)
塞巴斯蒂安(Sebastian)的答案不再对我有用(尽管在某个阶段它确实有用)。现在,我将执行以下操作,直到在Typescript核心中解决该问题为止(根据Sebastians答案中列出的问题):
handleUpdate (e:React.SyntheticEvent<HTMLInputElement>) {
const newState = {};
newState[e.currentTarget.name] = e.currentTarget.value;
this.setState(newState);
}
这很la脚,但是有效
答案 2 :(得分:0)
我认为这可以解决您的问题。
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>)
}
如果该值不在可能的属性值类型集中,这仍会适当地给出错误,但如果这些键不在可能的属性键集中,则不会给出错误。
Ref:https://github.com/DefinitelyTyped/DefinitelyTyped/issues/26635