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

React多泛型条件Typography组件类型定义问题求助

实现灵活的React Typography组件问题

我正在React中实现一个Typography组件,需要满足以下灵活需求:

  • variant属性为必填项
  • as属性为可选项:
    • 若as为字符串(代表原生HTML标签),需暴露该标签的对应属性
    • 若as为React元素,需暴露该React元素的属性
    • 若未定义as,则默认使用variant映射的元素

举个例子:当as="a"时,组件应支持href属性。

我编写了如下示例代码,单独测试Proxy类型时功能正常,但将其应用到React组件中时无法正常工作:

import React from "react";

const TypographyDefaultMapping = {
    h1: 'h1',
    h2: 'h2',
    h3: 'h3',
    'body-medium': 'span',
    label: 'span',
} as const;

export type TypographyVariants = keyof typeof TypographyDefaultMapping;

type Tags = keyof HTMLElementTagNameMap;

type AsType = undefined | Tags | React.FunctionComponent<any>;

type VariantsDefaultType<T extends TypographyVariants> = Omit<
    React.ComponentPropsWithoutRef<typeof TypographyDefaultMapping[T]>,
    'as'
> & {
    variant: TypographyVariants;
};

export type NewConditionalTypography<
    T extends AsType,
    V extends TypographyVariants
> = T extends undefined
    ? VariantsDefaultType<V> // Undefined "as" property, fallback to variant's default
    : T extends Tags
    ? {
        variant: TypographyVariants;
        as: Tags;
        bloup: boolean;
    } & React.ComponentPropsWithoutRef<T> // "as" property is a valid HTML tag
    : T extends React.FunctionComponent<any> // "as" property is a React element
    ? {
        variant: TypographyVariants;
        as: React.FunctionComponent<any>;
        bib: boolean;
    } & React.ComponentProps<T>
    : never;

type Proxy<T = unknown> = T extends {
    as: infer As extends AsType;
    variant: infer Var extends TypographyVariants;
}
    ? NewConditionalTypography<As, Var>
    : T extends {
        variant: infer Var extends TypographyVariants; // case of not defined "as"
    }
    ? NewConditionalTypography<undefined, Var> 
    : never;

const NewTypography = (props: Proxy) => (
    <div>Test: {JSON.stringify(props)}</div>
);

const Link = ({ linkClick }: { linkClick: () => void }) => (
    <button onClick={linkClick}>Test</button>
);

// Expected to get HTMLHeadingElement props + variant prop
type TestProxy = Proxy<{ variant: 'h2' }>;
     // ^?

// Expected to get HTMLSpanElement props + variant prop
type TestProxySpan = Proxy<{ variant: 'body-medium' }>;
     // ^?

// Expected to get HTMLAnchor props + variant prop
type TestProxy2 = Proxy<{ variant: 'h2'; as: 'a' }>;
     // ^?

// Expected to get Link element props + variant prop
type TestProxy3 = Proxy<{ variant: 'h2'; as: typeof Link }>;
     // ^?

const TestingComponent = () => (
    <div>
    // Should allow (and auto-complete) "href"
        <NewTypography variant="h2" />
    // Should allow (and auto-complete) "linkClick"
        <NewTypography
            variant="body-medium"
            as={Link}
        //   linkClick={() => console.log('Test')}
        />
    // Should not allow "href"
        <NewTypography variant="body-medium" as="span" href="www.example.com" />
    </div>
);

请问如何实现该需求,且该方案是否具备可行性?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 16:05:22