javascript - Typescript:作为两个接口之一的函数参数
问题描述
我在看这个问题,我认为这与我的问题有关。但是,它与我的用例有点不同。
我有一个名为的函数parseScanResults
接受一个作为对象的参数。对象可以是两种类型之一。但是,打字稿使用以下代码引发错误:
const ScanForm: React.FC<IScanFormProps> = ({ children, onSubmit, parseScanResults }) => {
const [scannerActive, toggleScannerActive] = useState(false);
const closeScanner = (): void => {
toggleScannerActive(false);
};
const handleScanResults = (results: IVoucherScanResults | IBlinkCardScanResults): 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>
);
};
import CreditCardBarcodeScanner from 'src/components/scanners/credit_card_barcode_scanner';
import { IVoucherScanResults, IScannerProps, IParsedScanResults } from '../scanners/card_scanners';
import ScanForm from './scan-form';
function CreditCardBarcodeForm(): JSX.Element {
const onSubmit = (data: { expMonth: string; expYear: string; securityCode: string; cardNumber: string }): void => {
// Do something with form data
console.log(data);
};
const parseScanResults = (results: IVoucherScanResults): IParsedScanResults => {
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 };
};
return (
<ScanForm onSubmit={onSubmit} parseScanResults={parseScanResults}>
{({ scannerActive, closeScanner, handleScanResults }: IScannerProps) => (
<CreditCardBarcodeScanner
scannerActive={scannerActive}
closeScanner={closeScanner}
handleScanResults={handleScanResults}
/>
)}
</ScanForm>
);
}
export default CreditCardBarcodeForm;
export interface IBlinkCardScanResults {
cardNumber: string;
cvv: string;
expiryDate: {
day?: number;
empty?: boolean;
month: number;
originalString?: string;
successfullyParsed?: boolean;
year: number;
};
}
export interface IVoucherScanResults {
text: string;
timestamp: number;
format: number;
numBits: number;
}
export interface IParsedScanResults {
cardString: string;
stringMonth: string;
stringYear: string;
}
export interface IScannerProps {
scannerActive: boolean;
closeScanner: () => void;
handleScanResults: (results: IVoucherScanResults | IBlinkCardScanResults) => void;
}
export interface IScanFormProps {
children: (props: ICardScannerProps) => React.ReactElement;
onSubmit: (data: { expMonth: string; expYear: string; securityCode: string; cardNumber: string }) => void;
parseScanResults: (results: IBlinkCardScanResults | IVoucherScanResults) => IParsedScanResults;
}
错误指出:
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)
解决方案
您的问题是,要么parseScanUtils
是一个以 a作为参数的函数,要么是一个以 a 作为参数的函数,而只有一个是正确的。在这种情况下,您的组件似乎正在接收两者中的第一个。IVoucherScanResults
IBlinkCardScanResults
要点是,拥有一个函数联合(其中每个函数都有一个特定的参数类型)和一个函数的参数是两种类型的联合之间是有区别的。
parseScanResults:
((results: IBlinkCardScanResults) => IParsedScanResults)
| ((results: IVoucherScanResults) => IParsedScanResults);
对比
parseScanResults:
((results: IBlinkCardScanResults | IVoucherScanResults) => IParsedScanResults)
编辑
您可以做的是使用泛型,而不是键入组件函数,您可以显式键入参数:
让我们首先使接口通用:
export interface IScanFormProps<T extends IBlinkCardScanResults | IVoucherScanResults> {
children: (props: ICardScannerProps) => React.ReactElement;
onSubmit: (data: { expMonth: string; expYear: string; securityCode: string; cardNumber: string }) => void;
parseScanResults: (results: T) => IParsedScanResults;
}
比你可以像这样更新你的功能组件:
const ScanForm = <T extends IBlinkCardScanResults | IVoucherScanResults>({ children, onSubmit, parseScanResults }: T) => {
和你的handleScanResults
功能:
const handleScanResults = (results: T): void => {
...rest of code...
}
那么剩下要做的就是调用所需类型的组件(例如IBlinkCardScanResults
):
<ScanForm<IBlinkCardScanResults> onSubmit={onSubmit} parseScanResults={parseScanResults}>
我相信它现在应该可以工作
推荐阅读
- sql - 如何将分区行号添加到 Azure 数据工厂?
- r - 将顶点查找表与边列表进行比较并将顶点标签分配给任何匹配的边的有效方法
- visual-studio-code - 为什么在 VS Code 中没有为我的自定义扩展显示语法突出显示?
- python - 如何从 Canvas python 获取信息?
- android - 如何在不事先知道 android kotlin 的大目录中有多少文件夹的情况下访问带有子文件夹的大目录中的文件?
- python - Pymysql无法导入python3
- java - 使用 XMLUnit 比较两个相似的 xml 文档,忽略节点文本值
- r - ggplot2上具有特定颜色的渐变
- javascript - 使用 jQuery $.ajax() 时无法重新加载 div
- azure - 使用 Az PowerShell 模块管理 Microsoft.ClassicCompute/domainNames