Pick 具有动态/计算键的类型

问题描述 投票:8回答:3

最新的@types/reactv15.0.6)利用TypeScript 2.1中为setState添加的功能,即Pick<S, K>。这是一件好事,因为现在的键入是正确的,因为在更新之前键入“不知道” setState正在合并this.state,而不是替换它。

此外,使用Pick使setState功能在允许的输入方面非常严格。无法再将未在组件定义中定义的属性添加到stateReact.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与动态键值一起使用吗?

reactjs generics typescript components
3个回答
11
投票

因此,在进行了更多研究之后,我可以提供上面代码中发生的情况的更多上下文。

[当您执行const name = 'Bob'之类的操作时,变量name的类型为'Bob' 字符串。但是,如果将const替换为letlet name = 'Bob'),则变量name的类型将为string

此概念称为“扩展”。基本上,这意味着类型系统尝试尽可能明确。由于无法重新分配const,因此TypeScript可以推断确切的类型。 let语句可以重新分配。因此,TypeScript将string的类型推断为name的类型。

const key = e.currentTarget.name as keyof Person也会发生同样的情况。 key将是(联合)类型"name"|"age",这正是我们想要的类型。 But

在表达式this.setState({ [key]: value });中变量key被(错误地)扩展为string

tl; dr;

看来TypeScript中有错误。我将问题发布到了Github仓库和TypeScript团队is investigating the problem。 :)

作为临时解决方法,您可以执行以下操作:

this.setState({ [key as any]: value });

3
投票

塞巴斯蒂安的回答对我不再有用(尽管在一个阶段它确实有用)。现在,我将执行以下操作,直到在Typescript核心中解决该问题为止(根据Sebastians答案中列出的问题):


0
投票

我认为这可能会解决您的问题。

© www.soinside.com 2019 - 2024. All rights reserved.