typescript react组件props如何通过某个属性的类型推断其它属性的值?

需求:react组件的props中value、onChange的参数value可通过valueType的值实现类型推断。例如当前valueType为string时,value的类型为string;当valueType为array时,value的类型为any[];

interface props {
   valueType: "string" |  "array";
   value: string | any[];
  onChange: (value: string|any[]) => void
}
// 这样写无法实现类型推断
阅读 3.3k
3 个回答
interface props<T> {
  value: T;
  onChange: (value: T) => void
}
type Props =
  | {
      valueType: 'string';
      value: string;
      onChange: (value: string) => void;
    }
  | {
      valueType: 'array';
      value: any[];
      onChange: (value: any[]) => void;
    };

我个人觉得还是保持数组的方式作为多选框的核心数据,传递参数时再根据需要使用split函数是比较好的方式。

你想要的是这种写法?

interface StringProps {
    valueType: "string"
    value: string
    onChange: (value: string) => void
}

interface ArrayProps {
    valueType: "array"
    value: any[]
    onChange: (value: any[]) => void
}

type CheckboxAutoProps = ArrayProps | StringProps

export function CheckboxAuto(props: CheckboxAutoProps) {
    const { valueType, value } = props
    switch (valueType) {
        case 'array':
            console.log('数组', value.filter(() => true))
            break
        case 'string':
            console.log('字符串', value.split('&'))
            break
        default:
            break;
    }
}

checkbox.tsx

import { useState } from "react"
import { nanoid } from "nanoid"

interface CheckboxProps<Value> {
    /**
     *【数组】选项显示的文字
     */
    name: readonly string[]
    /**
     *【数组】选项所代表的值
     */
    option: readonly Value[]

    /**
     *【数组】已选中的值
     */
    value: Value[]
    /**
     *【数组】状态更新过的已选中的值
     */
    onChange: (value: Value[]) => void
}

/**
 * 多选框组件,通过value和onChange可以配合useState使用
 * 
 * @param props 
 * 
 * name: 【数组】选项显示的文字
 * 
 * option: 【数组】选项所代表的值
 * 
 * value: 【数组】已选中的值
 * 
 * onChange:【数组】状态更新过的已选中的值
 * 
 * @example 举个栗子
 * 
 * const [choosed, setChoosed] = useState<string[]>([])
 * 
 * <Checkbox
 *      name={['A计划(15元)', 'B计划(39元)', 'C计划(99元,附赠一年大会员)']}
 *
 *      option={['A', 'B', 'C']}
 *
 *      value={choosed} onChange={setChoosed}></Checkbox>
 *
 * 
 * @returns 
 */
export function Checkbox<Value = any>(props: CheckboxProps<Value>) {
    const { onChange, name, value, option } = props

    // 多选框选中状态
    const [checked, setChecked] = useState<boolean[]>([])

    // 缓存全局ID,避免改变选择时,重新渲染会导致nanoid函数执行的问题
    const [uniqueKey] = useState(() => option.map(() => nanoid()))

    function onInputChange(changed: Value, key: number) {
        let newValueList: Value[] = []

        if (checked[key]) {
            newValueList = value.filter(v => v !== changed)
            checked[key] = false
        } else {
            newValueList = [...value, changed]
            checked[key] = true
        }

        setChecked([...checked])
        onChange([...newValueList])
    }

    const item = (name: string, optionItem: Value, key: number) => {
        return (
            <div key={key}>
                <input type='checkbox' id={`${uniqueKey[key]}`}
                    onChange={() => onInputChange(optionItem, key)}></input>
                <label htmlFor={`${uniqueKey[key]}`}>{name}</label>
            </div>
        )
    }

    return (
        <div>
            {option.map((optionItem, index) => item(name[index], optionItem, index))}
        </div>
    )
}

App.tsx

import { useState } from 'react'
import './App.css'
import { Checkbox } from './package/ui/chooser/muti/checkbox'


function App() {

  const [choosed, setChoosed] = useState<string[]>([])

  const [userChoosedRes, setUserChoosedRes] = useState<string[]>([])
  const httpRes = '选项1,选项2,选项3'

  return (
    <div className="App">
      <Checkbox
        name={['A计划(15元)', 'B计划(39元)', 'C计划(99元,附赠一年大会员)']}
        option={['A', 'B', 'C']}
        value={choosed} onChange={setChoosed}></Checkbox>

      <Checkbox
        name={httpRes.split(',')}
        option={httpRes.split(',')}
        value={userChoosedRes} onChange={setUserChoosedRes}></Checkbox>
    </div>
  )
}

export default App
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题