如何缩小使用第三方函数/类型的自定义组件返回的类型

问题描述 投票:0回答:1

我已经为 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
的值传递到我的函数中并执行一些条件返回,但它不起作用。

typescript typescript-generics
1个回答
0
投票

泛型在这里非常方便。它们基本上允许您根据输入动态推断和强制执行类型。

使用泛型,我们可以将代码重写为如下所示;

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中代码的上下文,这解释了如何使用泛型来解决您的问题。

© www.soinside.com 2019 - 2024. All rights reserved.