我已经为 Shopify 资源选择器设置了一个包装器组件。
import { useAppBridge } from '@shopify/app-bridge-react';
import { Button, type ButtonProps } from '@shopify/polaris';
import { useCallback } from 'react';
export type ResourcePickerSelectPayload = NonNullable<
Awaited<ReturnType<typeof shopify.resourcePicker>>
>;
interface ProductResourcePickerProps {
onSelect: (resources: ResourcePickerSelectPayload) => void;
options?: Parameters<typeof shopify.resourcePicker>[0];
buttonLabel?: string;
buttonProps?: Omit<ButtonProps, 'onClick'>;
}
export function ResourcePicker({
onSelect,
options = { type: 'product' },
buttonLabel = 'Select products',
buttonProps = {},
}: ProductResourcePickerProps) {
const shopify = useAppBridge();
const handleOpenPicker = useCallback(async () => {
const selected = await shopify.resourcePicker(options);
if (selected) {
onSelect(selected);
}
}, [onSelect, options, shopify]);
return (
<Button onClick={handleOpenPicker} {...buttonProps}>
{buttonLabel}
</Button>
);
}
shopify.ResourcePicker
的返回值如下:
type ResourcePickerApi = (options: ResourcePickerOptions) => Promise<SelectPayload<ResourcePickerOptions['type']> | undefined>;
这导致我的
ResourcePickerSelectPayload
成为:
type ResourcePickerSelectPayload = ResourceSelection<"product" | "variant" | "collection">[] & {
selection: ResourceSelection<"product" | "variant" | "collection">[];
}
我正在努力解决的是如何让
options.type
(产品、变体或集合)的值通过,以便我的组件返回缩小的类型。即如果 options.type === 'product'
那么 selected
将是 ResourceSelection<'product'>
。
ResourceSelection
类型未导出,因此除了我所拥有的之外,我不知道如何访问它。
我认为部分问题在于我的 ResourcePickerSelectPayload
不是通用的,但 ResourceSelection
是通用的。
我尝试将
options.type
的值传递到我的函数中并执行一些条件返回,但它不起作用。
泛型在这里非常方便。它们基本上允许您根据输入动态推断和强制执行类型。
使用泛型,我们可以将代码重写为如下所示;
interface ProductResourcePickerProps<
T extends "product" | "variant" | "collection"
> {
onSelect: (resources: ResourceSelection<T>[]) => void;
options?: { type: T } & Omit<ResourcePickerOptions, "type">;
buttonLabel?: string;
buttonProps?: Omit<ButtonProps, "onClick">;
}
export function ResourcePicker<T extends "product" | "variant" | "collection">({
onSelect,
options = { type: "product" } as { type: T },
buttonLabel = "Select resources",
buttonProps = {},
}: ProductResourcePickerProps<T>) {
const shopify = useAppBridge();
const handleOpenPicker = useCallback(async () => {
const selected = await shopify.resourcePicker(options);
if (selected?.selection) {
onSelect(selected.selection);
}
}, [onSelect, options, shopify]);
return (
<Button onClick={handleOpenPicker} {...buttonProps}>
{buttonLabel}
</Button>
);
}
所以一旦你打电话给
ResourcePicker
,onSelect
就已经知道进来了什么。像这样;
<ResourcePicker
onSelect={(selected) => {
// TypeScript shows ResourceSelection<'product'>[] as the type already
console.log(selected);
}}
options={{ type: 'product' }}
buttonLabel="Select products"
/>
对于它的价值,我检查了资源选择器文档,我认为这个包装器还有更多要做的事情,但重点关注OP中代码的上下文,这解释了如何使用泛型来解决您的问题。