使用动态/计算键选择<s,k =“”>类型

时间:2017-02-07 12:42:02

标签: reactjs generics typescript components

最新@types/reactv15.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"

除了拥有单独的updateNameupdateAge功能之外,我无法找到解决方案。有谁知道如何将Pick与动态键值一起使用?

3 个答案:

答案 0 :(得分:10)

因此,在做了更多研究之后,我可以提供一些关于上述代码中发生的事情的更多背景信息。

当您执行const name = 'Bob'之类的操作时,变量name的类型为'Bob' 而不是字符串。但是,如果您将const替换为letlet 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