Как можно извлечь типы пропсов из определения компонента?

Я разрабатываю компонент с поведением, аналогичным встроенному элементу <code>&lt;component :is /&gt;</code>, но с типизацией. С HTML-тегами всё работает хорошо, однако возникает трудность с извлечением типов пропсов для Vue-компонентов, и встроенный метод ExtractPropTypes не даёт результатов. <br/><br/> Можете привести пример, как правильно работать с пропсами в Vue-компонентах? <br/><br/> Например, для кнопки определены такие пропсы: <br/>
  • 15 ноября 2024 г. 10:43
Ответы на вопрос 2
В Vue 3 для определения и извлечения типов пропсов можно воспользоваться API `defineProps` и `extractPropTypes`. Позвольте привести пример, который поможет вам понять, как работать с типами пропсов, особенно в контексте создания компонента, который может отображать другие компоненты.

### Пример компонента кнопки

Предположим, у нас есть простой компонент кнопки, который принимает несколько пропсов:

```vue
<!-- Button.vue -->
<template>
  <button :class="`btn ${type}`" @click="onClick">{{ label }}</button>
</template>

<script lang="ts">
import { defineComponent, ExtractPropTypes } from 'vue';

const buttonProps = {
  label: {
    type: String,
    required: true,
  },
  type: {
    type: String,
    default: 'primary',
  },
  onClick: {
    type: Function,
    required: false,
  },
};

export const buttonPropTypes = ExtractPropTypes(buttonProps);

export default defineComponent({
  name: 'Button',
  props: buttonProps,
});
</script>
```

### Извлечение типов пропсов

Теперь, когда мы определили пропсы для кнопки, можно создать другой компонент, который будет использовать эту кнопку и извлекать типы пропсов.

```vue
<!-- WrapperComponent.vue -->
<template>
  <div>
    <Button v-bind="buttonProps" />
  </div>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import Button, { buttonPropTypes } from './Button.vue';

export default defineComponent({
  name: 'WrapperComponent',
  components: {
    Button,
  },
  data() {
    return {
      buttonProps: {
        label: 'Click me',
        type: 'success',
        // onClick: this.handleClick, // Можно указать соответствующий обработчик
      } as buttonPropTypes // Здесь мы явно указываем тип пропсов
    };
  },
  methods: {
    handleClick() {
      console.log('Button clicked');
    },
  },
});
</script>
```

### Использование в `<component :is="..."/>`

Если у вас есть компонент, который отображает другие компоненты в зависимости от переданного значения, вы можете сделать что-то подобное:

```vue
<!-- DynamicComponent.vue -->
<template>
  <component :is="component" v-bind="props" />
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import Button, { buttonPropTypes } from './Button.vue';

const componentsMap = {
  Button,
};

export default defineComponent({
  name: 'DynamicComponent',
  props: {
    component: {
      type: String,
      required: true,
    },
    props: {
      type: Object,
      required: true,
    },
  },
  setup(props) {
    return () => {
      const component = componentsMap[props.component];
      if (!component) {
        return null;
      }
      return <component {...props.props} />;
    };
  },
});
</script>
```

### Заключение

Таким образом, при работе с пропсами вы можете использовать `ExtractPropTypes`, чтобы извлекать типы и гарантировать типизацию данных при передаче их в ваши компоненты. Это повышает безопасность типов в вашем коде и облегчает понимание того, какие пропсы ожидает ваш компонент.

Не забывайте о том, что при работе с Vue в TypeScript вы можете также использовать интерфейсы для описания структуры ваших пропсов, что сделает ваш код более понятным и удобно структурированным.
type ComponentProps<ComponentDefinition> = ComponentDefinition extends { new (): { $props: infer P } } ? P : never;
Похожие вопросы