使用动态/计算键选择<S,K>类型

Seb*_*ald 8 generics components typescript reactjs

最新的@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>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

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; }'.
Run Code Online (Sandbox Code Playgroud)

即使类型key"name" | "age".

我无法找到一个解决方案,比拥有一个单独的其他updateNameupdateAge功能.有谁知道如何使用Pick动态键值?

Seb*_*ald 11

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

当你这样做const name = 'Bob'的变量的类型name'Bob' 不是字符串.但是,如果const用a 替换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中(错误地)扩展为a string.


TL;博士; 似乎TypeScript中存在一个错误.我将问题发布到Github repo,TypeScript团队正在研究这个问题.:)

作为临时解决方法,您可以:

this.setState({ [key as any]: value });
Run Code Online (Sandbox Code Playgroud)