Ошибка типа функции рендеринга Storybook v8 и Angular v18

Вопрос или проблема

У меня есть набор историй для компонента в Storybook 8 и Angular 18, которые показывают ошибку типов, когда компонент включает EventEmitter. Например:

class MyComponent {
  @Output() someEvent = new EventEmitter<any>();
  // другие свойства и методы
}

И простая история, например:

export default meta;
type Story = StoryObj<MyComponent>;

export const Basic: Story = {
  render: (args: MyComponent) => ({
    props: {
      ...args,
    },
  }),
  args: {},
};

Как в моей среде разработки (VS Code), так и при запуске в браузере я получаю ошибку типов и не могу запустить свои истории. Ошибка, кажется, несущественна и просто указывает на несоответствие типов (для справки, store – это служба в моем компоненте):

Тип ‘(args: MyComponent) => { props: { someEvent: EventEmitter<…>;
}; }’ недопустим для типа ‘ArgsStoryFn<AngularRenderer,
TransformInputSignalType<TransformOutputSignalType<TransformEventType>>>’.
Типы параметров ‘args’ и ‘args’ несовместимы.
Тип ‘TransformInputSignalType<TransformOutputSignalType<TransformEventType>>’
не имеет следующих свойств типа ‘MyComponent’: store

Если я удаляю любые @Output EventEmitters, проблема исчезает, но, как вы можете представить, мне нужны эти эмиттеры для работы моего компонента.

Я наткнулся на обходной путь, изменив тип StoryObj на ‘any’ вот так:

export default meta;
type Story = StoryObj<any>;

export const Basic: Story = {
  render: (args: MyComponent) => ({
    props: {
      ...args,
    },
  }),
  args: {},
};

Однако это не кажется правильным, и я подозреваю, что я просто делаю что-то не так.

Ответ или решение

Ошибка типа функции рендеринга в Storybook v8 и Angular v18: подробное объяснение и решение

При разработке компонентов на основе Angular и использовании Storybook для их документирования, вы можете столкнуться с рядом типовых ошибок. Одной из таких ошибок является несовпадение типов, возникающее, когда ваш компонент содержит EventEmitter. Давайте разберем вашу ситуацию более подробно и предложим решения.

Описание проблемы

В вашем компоненте используется EventEmitter, который объявляется следующим образом:

class MyComponent {
  @Output() someEvent = new EventEmitter<any>();
  // другие свойства и методы
}

При создании простого Story для этого компонента, вы получаете ошибку типов, касающуюся параметров функции render:

export default meta;
type Story = StoryObj<MyComponent>;

export const Basic: Story = {
  render: (args: MyComponent) => ({
    props: {
      ...args,
    },
  }),
  args: {},
};

Ошибка, с которой вы сталкиваетесь, гласит, что тип аргумента args несовместим с ожидаемым типом. Ваша IDE и браузер выдают сообщение о том, что TransformInputSignalType не содержит свойство store, которое определено в вашем компоненте:

Type '(args: MyComponent) => {...}' is not assignable to type 'ArgsStoryFn<AngularRenderer, ...>'.
Types of parameters 'args' and 'args' are incompatible. Type 'TransformInputSignalType' is missing the following properties from type 'MyComponent': store

Анализ проблемы

Основная причина возникновения данного типа ошибки заключается в том, что Storybook и Angular используют собственные системы типов, которые интерпретируют параметры по-разному, особенно в отношении выходных и входных свойств компонентов. Output свойства, такие как EventEmitter, добавляют определенные особенности к вашему компоненту, которые могут привести к несовпадениям.

Когда вы убираете @Output и EventEmitter, Storybook не сталкивается с проблемами сопоставления типов, так как становится проще определить структуру данных, передаваемых в render.

Решение через изменение типа StoryObj

Ваше временное решение, заключающееся в установлении типа StoryObj<any>, может устранить ошибку, но, как вы правильно заметили, это не является идеальной практикой. Использование any может скрывать реальные проблемы и привести к недостатку типизации.

Рекомендации по решению

  1. Определите входные свойства явно: Убедитесь, что вы определили все свойства вашего компонента в типе для StoryObj. Если ваш компонент нуждается в дополнительных свойствах, добавьте их в интерфейс Story:
interface MyComponentArgs {
  store: MyStoreService; // Замените на реальный тип вашего сервиса
  // Добавьте другие необходимые свойства
}
  1. Обновите StoryObj: Вместо использования any, установите правильный тип:
type Story = StoryObj<MyComponentArgs>;

export const Basic: Story = {
  render: (args: MyComponentArgs) => ({
    props: {
      ...args,
    },
  }),
  args: {
    store: new MyStoreService(), // Или другой способ предоставить ваш сервис
  },
};
  1. Проверка конфигурации Storybook: Убедитесь, что ваши зависимости Storybook и Angular обновлены до последних версий. Порой, такие проблемы могут быть исправлены в более новых релизах.

  2. Документация и примеры: Обратитесь к документации Storybook и Angular для более подробной информации о том, как правильно интегрировать эти технологии.

Заключение

Правильная типизация и конфигурация Storybook с Angular необходимы для обеспечения гладкого процесса разработки. Понимание специфик типов, используемых в обеих средах, может помочь избежать потенциальных проблем. Если вы продолжаете сталкиваться с трудностями, не стесняйтесь обращаться за помощью в сообщества разработчиков, такие как Stack Overflow или специализированные форумы.

Эффективная работа с типами и событиями — это залог успешного и безопасного кода в любой значимой разработке на Angular.

Оцените материал
Добавить комментарий

Капча загружается...