You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何收窄调用第三方函数的自定义组件返回类型

解决Shopify Resource Picker组件的类型收窄问题

问题背景

封装Shopify Resource Picker组件时,当前实现的ResourcePickerSelectPayload是所有资源类型的联合类型,无法根据传入的options.type(product/variant/collection)自动收窄返回值类型。比如传入type: 'product'时,希望onSelect的参数类型自动变为对应product的ResourceSelection类型,而非联合类型。且由于ResourceSelection未被Shopify导出,无法直接引用。

解决方案

将组件定义为泛型组件,基于ResourcePickerOptions的type字段做类型约束,利用TypeScript的类型推断自动推导对应返回类型:

1. 泛型化组件Props和类型定义

修改Props为泛型接口,同时调整选择结果类型为泛型,通过ReturnType和Parameters从shopify.resourcePicker的类型中提取对应类型:

import { useAppBridge } from '@shopify/app-bridge-react';
import { Button, type ButtonProps } from '@shopify/polaris';
import { useCallback } from 'react';

// 泛型选择结果类型,根据传入的资源类型自动推导
export type ResourcePickerSelectPayload<ResourceType extends 'product' | 'variant' | 'collection'> = NonNullable<
  Awaited<ReturnType<typeof shopify.resourcePicker<ResourceType>>>
>;

// 泛型化Props接口,绑定资源类型与options.type
interface ResourcePickerProps<ResourceType extends 'product' | 'variant' | 'collection'> {
  onSelect: (resources: ResourcePickerSelectPayload<ResourceType>) => void;
  options?: Parameters<typeof shopify.resourcePicker<ResourceType>>[0];
  buttonLabel?: string;
  buttonProps?: Omit<ButtonProps, 'onClick'>;
}

// 泛型化组件,默认类型设为product保持原有行为
export function ResourcePicker<ResourceType extends 'product' | 'variant' | 'collection' = 'product'>({
  onSelect,
  options = { type: 'product' as ResourceType },
  buttonLabel = 'Select products',
  buttonProps = {},
}: ResourcePickerProps<ResourceType>) {
  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>
  );
}

2. 使用示例(自动类型收窄)

当传入不同的options.type时,TypeScript会自动推导onSelect的参数类型:

// 选择product时,参数自动匹配product类型结构
<ResourcePicker
  options={{ type: 'product' }}
  onSelect={(selected) => {
    console.log(selected.selection[0].title); // 类型安全,product包含title字段
  }}
/>

// 选择variant时,参数自动切换为variant类型结构
<ResourcePicker
  options={{ type: 'variant' }}
  buttonLabel="Select variants"
  onSelect={(selected) => {
    console.log(selected.selection[0].price); // 类型安全,variant包含price字段
  }}
/>

核心原理说明

之前的实现中,ResourcePickerSelectPayload是固定的联合类型,没有和options.type建立关联。通过泛型将ResourceType绑定到options.type和onSelect的参数类型,让TypeScript能根据传入的具体类型自动推导收窄后的类型,无需直接引用未导出的ResourceSelection。

内容的提问来源于stack exchange,提问作者NicO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 01:22:41