首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >ts(2322):不能将'Dispatch<SetStateAction<string>>‘赋值给类型'(value: OptionValue) => Dispatch<SetStateAction<string>>’

ts(2322):不能将'Dispatch<SetStateAction<string>>‘赋值给类型'(value: OptionValue) => Dispatch<SetStateAction<string>>’
EN

Stack Overflow用户
提问于 2021-04-29 16:36:23
回答 2查看 233关注 0票数 1

我正在学习Typescript generic与React的集成,阅读this article并遵循文章的代码,但得到了这个错误:

代码语言:javascript
运行
复制
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>'

下面是我的全部代码:

代码语言:javascript
运行
复制
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组件中使用泛型

代码语言:javascript
运行
复制
/* 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来解决这个问题,如下所示:

代码语言:javascript
运行
复制
const [target, setTarget] = useState<OptionValue>('es2019')

但是我发现这个article并没有做到这一点,而且这种方式也不是typescript通用的,对吧?

EN

回答 2

Stack Overflow用户

发布于 2021-04-29 17:03:31

在您的参考文章中,targets的所有values都是stringnumber。在您的代码中,targetsvalues同时包含这两个参数。

当你调用

代码语言:javascript
运行
复制
useState('es2019')

我认为Typescript推断target的类型是string (它不能推断这也可能是number)。

所以有了

代码语言:javascript
运行
复制
const [target, setTarget] = useState<OptionValue>('es2019')

你基本上是在告诉typescript:,我想用一个string来初始化它,但它也可以是一个数字。

一个奇怪的工作也是:

代码语言:javascript
运行
复制
const [target, setTarget] = useState(targets[6].value);
票数 0
EN

Stack Overflow用户

发布于 2021-04-29 17:04:00

本文没有这样做,因为targets中的value的类型始终是stringnumber。所以他可以声明状态target而不需要OptionValue,只需要target的类型与value的类型相同。

在您的示例中,targets中的value同时具有stringnumber类型。因此,在声明状态target时,需要添加类型OptionValue

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67313822

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档