[英]Pick<S, K> type with dynamic/computed keys
The latest @types/react
( v15.0.6
) make use of features added in TypeScript 2.1 for setState
, namely Pick<S, K>
.最新的
@types/react
( v15.0.6
) 使用了 TypeScript 2.1 中为setState
添加的功能,即Pick<S, K>
。 Which is a good thing, because now the typings are correct, because before the update typings "didn't know" that setState
is merging this.state
, rather than replacing it.这是一件好事,因为现在输入是正确的,因为在更新输入之前“不知道”
setState
正在合并this.state
,而不是替换它。
Also, using Pick
makes the setState
function very strict in terms of allowed input.此外,使用
Pick
使setState
函数在允许的输入方面非常严格。 It is no longer possible to add properties to the state
that aren't defined in the component definition (second generic of React.Component
.不再可能向组件定义中未定义的
state
添加属性( React.Component
的第二个泛型。
But it is also harder to define a dynamic update handler.但定义动态更新处理程序也更难。 For example:
例如:
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>
);
}
}
The setState
function will throw the following error 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; }'.
even though the type of key
is "name" | "age"
即使
key
的类型是"name" | "age"
"name" | "age"
. "name" | "age"
。
I can not find a solution for this, other than having a separate updateName
and updateAge
function.除了具有单独的
updateName
和updateAge
函数之外,我找不到解决方案。 Does anyone know how to use Pick
with dynamic key values?有谁知道如何将
Pick
与动态键值一起使用?
So after doing more research I can provide a little more context on what is happening in the above code.因此,在进行更多研究之后,我可以提供更多有关上述代码中发生的情况的上下文。
When you do something like const name = 'Bob'
the type of the variable name
is 'Bob'
not string.当您执行类似
const name = 'Bob'
的操作时,变量name
的类型是'Bob'
而不是字符串。 However, if you replace the const
with a let
( let name = 'Bob'
) the variable name
will be of type string
.但是,如果您将
const
替换为let
( let name = 'Bob'
),则变量name
将为string
类型。
This concept is called "widening".这个概念叫做“拓宽”。 Basically, it means that the type system tries to be as explicit as possible.
基本上,这意味着类型系统试图尽可能明确。 Because
const
can not be reassigned TypeScript can infer the exact type.因为
const
不能被重新赋值,TypeScript 可以推断出确切的类型。 let
statements can be reassigned. let
语句可以重新赋值。 Thus, TypeScript will infer string
(in the above example) as the type of name
.因此,TypeScript 会将
string
(在上面的示例中)推断为name
的类型。
The same is happening with const key = e.currentTarget.name as keyof Person
. const key = e.currentTarget.name as keyof Person
也会发生同样的情况。 key
will be of (union) type "name"|"age"
, which is exactly what we want it to be. key
将是(联合)类型"name"|"age"
,这正是我们想要的。 But in the expression this.setState({ [key]: value });
但是在表达式中
this.setState({ [key]: value });
variable key
is (incorrectly) widened to a string
.变量
key
被(错误地)扩展为string
。
tl;dr; TL;博士; It seems like there is a bug in TypeScript.
TypeScript 中似乎存在错误。 I posted the issue to the Github repo and the TypeScript team is investigating the problem .
我将问题发布到 Github 存储库,TypeScript 团队正在调查该问题。 :)
:)
As a temporary workaround you can do:作为临时解决方法,您可以执行以下操作:
this.setState({ [key as any]: value });
The answer from Sebastian no longer works for me (though at one stage it did).塞巴斯蒂安的回答不再对我有用(尽管在某个阶段确实如此)。 I now do the following until it is resolved in Typescript core (as per the issue listed in Sebastians answer):
我现在执行以下操作,直到它在 Typescript 核心中得到解决(根据 Sebastians 回答中列出的问题):
handleUpdate (e:React.SyntheticEvent<HTMLInputElement>) {
const newState = {};
newState[e.currentTarget.name] = e.currentTarget.value;
this.setState(newState);
}
It's lame, but it works这很蹩脚,但它有效
I think this might solve your problem.我认为这可能会解决您的问题。
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>)
}
This will still give an error appropriately if the value is not in the set of possible property value types, but will not give you an error if the keys are not within the set of possible property keys.如果该值不在可能的属性值类型集中,这仍然会适当地给出错误,但如果键不在可能的属性键集中,则不会给您错误。
Ref:https://github.com/DefinitelyTyped/DefinitelyTyped/issues/26635参考:https ://github.com/DefinitelyTyped/DefinitelyTyped/issues/26635
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.