使用React和Typescript描述咖喱状态处理程序的类型

时间:2019-02-06 20:31:42

标签: reactjs typescript generics type-inference

我试图描述处理变更事件以反映状态值的函数的类型。

所需的实现如下所示:

handleChange: ChangeHandler<State> = field => value =>
    this.setState({ [field]: value });

给出状态:

interface State {
  title: string;
  description: string | null;
}

一个人可以通过以下方式将此功能传递给组件:

<TextComponent onChange={this.handleChange('title')} />

解决这个问题的最佳尝试是创建以下类型:

type ChangeHandler<S> = <K extends keyof S, V extends S[K]>(key: K) => (value: V) => void;

但是,这似乎仅在状态的所有属性都是可选的时才有效。我无法使它与可选属性和非可选属性的状态一起使用。

编译器错误:

  

[ts]类型为'{[x:string]:V; }'不可分配给   'State |类型的参数(((prevState:只读,props:   只读)=>状态|   选择| null)|选择<...> |空”。
  输入'{[x:string]:V; }'缺少以下属性   输入“ Pick”:标题,说明[2345]

2 个答案:

答案 0 :(得分:1)

根本原因

这是由带有TypeScript的known issue引起的,其中扩展了由文字统一体组成的计算属性名称。

handleChange中,field的类型从'title' | 'description'扩展到string,这导致this.setState由于{{1} }的类型已定义。

下面是this.setState的简化定义:

setState

将该定义应用于function setState<K extends keyof State>(s: Pick<State, K>): void { console.log(s); } 时,上面的handleChange变成K,而'title' | 'description'参数变成s,这实际上与{ {1}}界面。

因此,鉴于我们的Pick<State, 'title' | 'description'>已扩展为State并且field在这种情况下接受string,我们将得到您看到的错误正在使用以下类型调用this.setState

State

无法分配给this.setState,因为缺少必需的参数{ [x: string]: V } State

解决方案

我们最好的选择是使用类型断言在保持类型检查的同时使错误消失。更新的定义如下:

title

请参见包含以上代码的this playground link


请参见discussion,以了解有关DefinitelyTyped的特定问题的替代解决方案/方法。

答案 1 :(得分:0)

您不得定义V extends S[K],因为您可以按如下所示直接内联此声明:

type ChangeHandler<S> = <K extends keyof S>(key: K) => (value: S[K]) => void;