Как задать значение по умолчанию для defineProps во Vue с TypeScript
Что проверяют
Знаете ли вы, что defineProps это макрос компилятора <script setup>, и как задать значения по умолчанию при объявлении пропсов через тип. В актуальном Vue правильных способов два, и хорошо назвать оба. Следом спрашивают про дефолты для массивов и объектов и про реактивность при деструктуризации.
Как отвечать
Классический способ через withDefaults:
<script setup lang="ts">
interface Props {
title: string
size?: 'sm' | 'md'
items?: string[]
}
const props = withDefaults(defineProps<Props>(), {
size: 'md',
items: () => [],
})
</script>Ключевые детали:
- импорт не нужен:
definePropsиwithDefaultsэто макросы, компилятор разворачивает их внутри<script setup>, и в итоговом коде их нет. Импорт изvueлишний, компилятор об этом предупредит; - ссылочные типы через фабрику: для массивов и объектов в
withDefaultsпередают функцию() => [], иначе экземпляры компонента делили бы один объект; - деструктуризация: с Vue 3.5 можно писать
const { size = 'md' } = defineProps<Props>(). Компилятор сохраняет реактивность, превращая обращения кsizeвprops.size, а значение по умолчанию задаётся обычным синтаксисом JavaScript; - типы: дефолт имеет смысл только для необязательного пропа с
?, и послеwithDefaultsTypeScript уже не считаетprops.sizeвозможнымundefined.
Где спотыкаются
Пишут defineProps в обычном <script lang="ts"> без setup и импортируют его из vue. Там макрос не работает, в таком компоненте пропсы объявляют через defineComponent и опцию props.
Передают деструктурированный проп прямо в watch(size, ...) или в composable. Туда уходит текущее значение, а не реактивный источник, и слежение не срабатывает. Нужен геттер watch(() => size, ...) или toRef(() => size).
Забывают про приведение булевых пропсов: необязательный disabled?: boolean, который не передали, внутри компонента равен false, а не undefined. Проверки на undefined не сработают, а дефолт true для такого пропа нужно задавать явно.