文件
Storybook 文件

使用 TypeScript 編寫故事

TypeScript 中編寫故事可以提高您的生產力。您不必在檔案之間跳轉來查找元件的屬性。您的程式碼編輯器會提醒您缺少必要的屬性,甚至會自動完成屬性值,就像在應用程式中使用元件一樣。此外,Storybook 會推斷這些元件類型以自動產生 控制項表格。

Storybook 具有內建的 TypeScript 支援,因此您可以零設定即可開始使用。

使用 MetaStoryObj 鍵入故事

在編寫故事時,有兩個方面對於鍵入很有幫助。第一個是元件中繼資料,它描述和設定元件及其故事。在 CSF 檔案中,這是預設匯出。第二個是故事本身

Storybook 為每個都提供實用程式類型,分別命名為 MetaStoryObj。以下是使用這些類型的 CSF 檔案範例

Button.stories.ts
// Replace your-renderer with the renderer you are using (e.g., react, vue3, etc.)
import type { Meta, StoryObj } from '@storybook/your-renderer';
 
import { Button } from './Button';
 
const meta: Meta<typeof Button> = {
  component: Button,
};
export default meta;
 
type Story = StoryObj<typeof Button>;
 
export const Basic: Story = {};
 
export const Primary: Story = {
  args: {
    primary: true,
  },
};

屬性類型參數

MetaStoryObj 類型都是泛型,因此您可以為它們提供元件類型或元件的屬性類型(例如,Meta<typeof Button>typeof Button 部分)的可選屬性類型參數。這樣做,TypeScript 會阻止您定義無效的參數,並且所有裝飾器Play 函數載入器都會鍵入其函數引數。

上面的範例會傳遞元件類型。請參閱鍵入自訂參數以取得傳遞屬性類型的範例。

使用 satisfies 以獲得更好的類型安全

如果您使用的是 TypeScript 4.9+,您可以利用新的 satisfies 運算子來取得更嚴格的類型檢查。現在,您將收到遺失必要引數的類型錯誤,而不僅僅是無效的引數。

使用 satisfies 套用故事的類型有助於在跨故事共用 Play 函數時維護類型安全。如果沒有它,TypeScript 會擲回錯誤,表示 play 函數可能未定義。satisfies 運算子會讓 TypeScript 推斷 Play 函數是否已定義。

最後,使用 satisfies 可讓您將 typeof meta 傳遞給 StoryObj 泛型。這會通知 TypeScript metaStoryObj 類型之間的連線,這可讓它從 meta 類型推斷 args 類型。換句話說,TypeScript 會瞭解引數可以在故事和中繼資料層級定義,並且在中繼資料層級定義了必要引數,但在故事層級未定義時,不會擲回錯誤。

輸入自訂參數

有時候,故事需要定義組件 props 中未包含的參數。針對這種情況,您可以使用交集型別來組合組件的 props 型別和您的自訂參數型別。例如,以下是如何使用 footer 參數來填充子組件

Page.stories.ts|tsx
import type { Meta, StoryObj } from '@storybook/react';
 
import { Page } from './Page';
 
type PagePropsAndCustomArgs = React.ComponentProps<typeof Page> & { footer?: string };
 
const meta: Meta<PagePropsAndCustomArgs> = {
  component: Page,
  render: ({ footer, ...args }) => (
    <Page {...args}>
      <footer>{footer}</footer>
    </Page>
  ),
};
export default meta;
 
type Story = StoryObj<PagePropsAndCustomArgs>;
 
export const CustomFooter: Story = {
  args: {
    footer: 'Built with Storybook',
  },
};