我试图描述处理变更事件以反映状态值的函数的类型。
所需的实现如下所示:
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]
答案 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;