我正在学习Typescript generic与React的集成,阅读this article并遵循文章的代码,但得到了这个错误:
Type 'Dispatch<SetStateAction<string>>' is not assignable to type '(value: OptionValue) => void'.
Types of parameters 'value' and 'value' are incompatible.
Type 'OptionValue' is not assignable to type 'SetStateAction<string>'.
Type 'number' is not assignable to type 'SetStateAction<string>'.ts(2322)
Select.tsx(15, 3): The expected type comes from property 'onChange' which is declared here on type 'IntrinsicAttributes & ISelectProps<OptionValue>'
下面是我的全部代码:
import React, { useState } from 'react'
import Select from './Select'
const App: React.FC = () => {
const targets = [
{ value: 'es3', label: 'ECMAScript 3' },
{ value: 'es5', label: 'ECMAScript 5' },
{ value: 'es2015', label: 'ECMAScript 2015' },
{ value: 'es2016', label: 'ECMAScript 2016' },
{ value: 'es2017', label: 'ECMAScript 2017' },
{ value: 'es2018', label: 'ECMAScript 2018' },
{ value: 'es2019', label: 'ECMAScript 2019' },
{ value: 2019, label: 'ECMAScript 2019' },
]
const [target, setTarget] = useState('es2019')
return (
<>
{/* <Select value={target} onChange={(value) => setTarget(value)} /> */}
<Select options={targets} value={target} onChange={setTarget} />
</>
)
}
export default App
在此Select
组件中使用泛型
/* eslint-disable react/destructuring-assignment */
import React, { useCallback } from 'react'
export type OptionValue = string | number
export type Option<T extends OptionValue> = {
value: T
label: string
}
interface ISelectProps<T extends OptionValue> {
options: Option<T>[]
value: T
onChange: (value: T) => void
}
const Select = <T extends OptionValue>(props: ISelectProps<T>) => {
const { options, onChange } = props
const handleOnChange = useCallback((e: React.FormEvent<HTMLSelectElement>) => {
const { selectedIndex } = e.currentTarget
const selectedOption = options[selectedIndex]
onChange(selectedOption.value)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
return (
// eslint-disable-next-line unicorn/consistent-destructuring
<select value={props.value} onChange={handleOnChange}>
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
)
}
export default React.memo(Select)
codesandbox是here
我知道我可以显式地将OptionValue
类型传递给useState
来解决这个问题,如下所示:
const [target, setTarget] = useState<OptionValue>('es2019')
但是我发现这个article并没有做到这一点,而且这种方式也不是typescript通用的,对吧?
发布于 2021-04-29 17:03:31
在您的参考文章中,targets
的所有values
都是string
或number
。在您的代码中,targets
的values
同时包含这两个参数。
当你调用
useState('es2019')
我认为Typescript推断target
的类型是string
(它不能推断这也可能是number
)。
所以有了
const [target, setTarget] = useState<OptionValue>('es2019')
你基本上是在告诉typescript:,我想用一个string
来初始化它,但它也可以是一个数字。
一个奇怪的工作也是:
const [target, setTarget] = useState(targets[6].value);
发布于 2021-04-29 17:04:00
本文没有这样做,因为targets
中的value
的类型始终是string
或number
。所以他可以声明状态target
而不需要OptionValue
,只需要target
的类型与value
的类型相同。
在您的示例中,targets
中的value
同时具有string
和number
类型。因此,在声明状态target
时,需要添加类型OptionValue
https://stackoverflow.com/questions/67313822
复制相似问题