React TypeScript传递Props给Hook时的类型错误求助
解决useInput Hook的TypeScript类型不匹配问题
看起来你遇到的是TypeScript对数组返回值的类型推断问题,以及组件props和Hook返回值之间的类型兼容性问题。咱们一步步来解决,完全不用妥协类型规范:
问题根源分析
- useInput返回值的类型推断偏差:你的useInput返回的是
[value, onChange, reset]数组,TypeScript默认会把它推断成(string | OnChangeType | (() => void))[]的联合数组类型,而非固定顺序的元组类型。当你把这个返回的onChange传给Input组件时,TS会认为它可能是string或其他类型,直接触发类型不兼容警告。 - Input组件props的类型瑕疵:你给onChange设置了默认值
null,但useInput返回的onChange是必填函数,这会导致类型冲突;另外onBlur函数的参数没有明确类型,也会触发类型检查警告。
具体解决方案
1. 给useInput定义明确的元组返回类型
修改useInput.tsx,通过as const强制TS将返回值推断为只读元组,固定每个位置的类型:
import { useState, ChangeEvent } from "react"; export type OnChangeType = (event: ChangeEvent<HTMLInputElement>) => void; const useInput = (initialValue = "") => { const [value, setValue] = useState(initialValue); const reset = () => setValue(""); const onChange: OnChangeType = e => { setValue(e.target.value); }; // 明确指定返回值为固定顺序的元组类型 return [value, onChange, reset] as const; }; export default useInput;
2. 修正Input组件的props类型与逻辑
修改Input.tsx里的类型定义和props处理,解决类型冲突与细节问题:
import React, { useState, ChangeEvent } from "react"; import styled, { css } from "styled-components"; import type { OnChangeType } from "./hooks/useInput"; interface ILabelProps { hasContent: boolean; } const hasContentCSS = () => css` border: 5px solid royalblue; `; // 补全styled.label的语法结构 const Label = styled.label<ILabelProps>` display: block; ${props => props.hasContent && hasContentCSS()} `; interface IInputProps { readonly type?: string; readonly name: string; readonly label: string; value?: string | number | string[] | null; defaultValue?: string | number | string[] | null; // 调整onChange类型为可选函数,移除null的允许值 readonly onChange?: OnChangeType; } export const Input = ({ name = "email", label, value = null, defaultValue = null, onChange }: IInputProps) => { // 初始化hasContent时优先判断受控值value const [hasContent, setHasContent] = useState(() => { if (value !== null) return !!String(value); return !!defaultValue; }); // 给onBlur的参数明确string类型 const onBlur = (inputValue: string) => { setHasContent(inputValue.length > 0); }; return ( <Label hasContent={hasContent}> <input type="text" name={name} // 简化props传递逻辑,用空值合并运算符替代冗余判断 {...(defaultValue !== null ? { defaultValue } : { value: value ?? "" })} {...(onChange && { onChange })} onBlur={e => onBlur(e.target.value)} /> <span>{label}</span> </Label> ); };
3. 正确使用useInput与Input组件
现在你可以安全地解构useInput的返回值,传递给Input组件,不会再有类型错误:
import useInput from "./hooks/useInput"; import { Input } from "./Input"; const App = () => { const [emailValue, emailOnChange, resetEmail] = useInput(""); return ( <div> <Input name="email" label="Email" value={emailValue} onChange={emailOnChange} /> <button onClick={resetEmail}>Reset Email</button> </div> ); }; export default App;
这样所有TypeScript类型检查都会通过,同时保持了代码的类型安全性与规范。
内容的提问来源于stack exchange,提问作者Héctor León
相关产品推荐
相关产品推荐

