Typescript函数参数为两个接口之一时类型不匹配报错如何解决
错误内容如下:
Type '(results: IVoucherScanResults) => IParsedScanResults' is not assignable to type '(results: IBlinkCardScanResults | IVoucherScanResults) => IParsedScanResults'. Types of parameters 'results' and 'results' are incompatible. Type 'IBlinkCardScanResults | IVoucherScanResults' is not assignable to type 'IVoucherScanResults'. Type 'IBlinkCardScanResults' is missing the following properties from type 'IVoucherScanResults': text, timestamp, format, numBitsts(2322)
错误原因
你在IScanFormProps中定义的parseScanResults函数要求可以接收IBlinkCardScanResults | IVoucherScanResults两种类型的参数,但你实际传入CreditCardBarcodeForm的parseScanResults只支持接收IVoucherScanResults单种类型。TypeScript做类型校验时,认为如果后续传入IBlinkCardScanResults类型的参数,当前的parseScanResults无法处理,因此抛出了类型不兼容的错误。
解决方案
方案1:将ScanForm改造为泛型组件(最推荐)
适合需要适配多种扫描结果类型的场景,通过泛型动态约束入参类型:
首先修改ScanForm的类型定义:
// 定义泛型T,约束为两种扫描结果的联合类型 interface IScanFormProps<T extends IVoucherScanResults | IBlinkCardScanResults> { children: (props: IScannerProps<T>) => React.ReactElement; onSubmit: (data: { expMonth: string; expYear: string; securityCode: string; cardNumber: string }) => void; parseScanResults: (results: T) => IParsedScanResults; } interface IScannerProps<T extends IVoucherScanResults | IBlinkCardScanResults> { scannerActive: boolean; closeScanner: () => void; handleScanResults: (results: T) => void; } // 组件声明时传入泛型 const ScanForm = <T extends IVoucherScanResults | IBlinkCardScanResults>({ children, onSubmit, parseScanResults }: IScanFormProps<T>) => { const [scannerActive, toggleScannerActive] = useState(false); const closeScanner = (): void => { toggleScannerActive(false); }; const handleScanResults = (results: T): void => { const { cardString, stringMonth, stringYear } = parseScanResults(results); setValue('cardNumber', cardString); setValue('expMonth', stringMonth); setValue('expYear', stringYear); toggleScannerActive(false); }; return ( <Form onSubmit={handleSubmit(onSubmit)}> {children({ scannerActive, closeScanner, handleScanResults })} </Form> ); };
使用时无需额外改动,TypeScript会自动推断泛型类型为IVoucherScanResults,不会再抛出错误。
方案2:为parseScanResults添加类型收窄逻辑
如果不需要泛型,也可以直接修改传入的parseScanResults,让它支持处理两种类型的入参,符合类型定义要求:
const parseScanResults = (results: IVoucherScanResults | IBlinkCardScanResults): IParsedScanResults => { // 判断是否是IVoucherScanResults类型 if ('text' in results) { const { text } = results; const [cardString, expirationString] = text.slice().split('/'); const stringMonth = expirationString.slice(0, 2); const stringYear = expirationString.slice(2, 4); return { cardString, stringMonth, stringYear }; } // 剩下的就是IBlinkCardScanResults类型,做对应处理 else { const { cardNumber, expiryDate } = results; return { cardString: cardNumber, stringMonth: String(expiryDate.month).padStart(2, '0'), stringYear: String(expiryDate.year).slice(-2) }; } };
方案3:使用类型断言(不推荐)
如果你确定当前场景下绝对不会传入IBlinkCardScanResults类型的结果,可以用类型断言绕过校验:
<ScanForm onSubmit={onSubmit} parseScanResults={parseScanResults as (results: IBlinkCardScanResults | IVoucherScanResults) => IParsedScanResults} > {/* 子组件内容 */} </ScanForm>
该方案绕过了TypeScript的类型检查,后续如果传入不符合预期的参数可能会引发运行时错误,仅建议临时调试时使用。
内容的提问来源于stack exchange,提问作者user6347891
相关产品推荐
相关产品推荐

