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

如何避免Storybook控件中cva生成的null值选项或实现默认回退

使用CVA创建按钮变体时解决Storybook控件出现null选项的问题

我用class-variance-authority(简称cva)定义按钮变体,并通过VariantProps推断按钮Props类型:

const variants = cva(
  {
    variants: {
      intent: {
        primary: [
          ...
        ],
        secondary: [
          ...
        ],
        ghost: [
          ...
        ],
      },
      size: {
        ...
      },
    },
    defaultVariants: {
      intent: "primary",
      size: "md",
    },
  }
);

type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
  VariantProps<typeof variants>

应用运行正常,手动传入intent或使用默认值都没问题,但Storybook的intent控件里除了定义的变体选项,还多出个null选项;选择null后按钮不会应用任何变体样式(预期应回退到默认样式)。目前只能通过在ButtonProps中添加额外类型覆盖cva的推断类型来消除null:

type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
  VariantProps<typeof variants> & {
     intent?: string;
  };

以下是不覆盖cva推断类型的两种解决方案:

方案一:直接移除Storybook控件的null选项

在Storybook的参数配置中,给intent控件指定可选值为cva定义的变体,并禁用null选项:

// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';

const meta: Meta<typeof Button> = {
  component: Button,
  argTypes: {
    intent: {
      control: {
        type: 'select',
        options: ['primary', 'secondary', 'ghost'],
        allowNull: false,
      },
    },
  },
};

export default meta;
type Story = StoryObj<typeof Button>;

export const Primary: Story = {
  args: {
    intent: 'primary',
  },
};

这样控件只会显示你定义的三个intent选项,不再出现null。

方案二:让null触发默认样式

修改按钮组件逻辑,将null值替换为cva的默认变体值,不改动类型定义:

import { cva, VariantProps } from 'class-variance-authority';

const variants = cva(/* 保持原有的变体定义 */);

type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
  VariantProps<typeof variants>;

export const Button = ({ intent, size, ...props }: ButtonProps) => {
  // 用空值合并运算符处理null,回退到默认值
  const resolvedIntent = intent ?? 'primary';
  const resolvedSize = size ?? 'md';
  
  return (
    <button
      className={variants({ intent: resolvedIntent, size: resolvedSize })}
      {...props}
    />
  );
};

这样即使Storybook传入null,组件也会自动使用默认的primary样式,同时保留cva原本的类型推断逻辑,无需覆盖ButtonProps。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 21:40:05