12

I'm building an app with Vue 3 and TS 4.4 and bundled with Vite 2. I've got a LoginPage.vue file with these contents:

<script lang="ts" setup>
const props = defineProps<{
  message?: string;
  redirectOnSubmit?: boolean;
  showRegisterLink?: boolean;
}>();

console.log({ ...props });
</script>

<template>
  ... login form and whatnot
</template>

This component is being passed to vue-router

export const router = createRouter({
  history: createWebHistory(),
  routes: [
    { name: RouteName.LOGIN, path: "/login", component: LoginPage },
    { name: RouteName.REGISTER, path: "/register", component: RegisterPage },
  ],
});

The problem I'm having is when the login page setup script gets run, it logs this:

{ redirectOnSubmit: false, showRegisterLink: false, message: undefined }

Why are my optional boolean props being forced to false instead of undefined? Is there any way to turn this off? If I switch message to message?: boolean, it also gets switched to false.

I'd like to default these props to true if nothing is passed, but as-is there's no way for me to distinguish between passing false and omitting the props entirely.

2
  • Can you share your component that receives props ? Commented Oct 26, 2021 at 20:27
  • @Batuhan That's the LoginPage.vue component. It's passed directly to vue-router, so it's not being passed any props. That's the problem. Vue is acting like the LoginPage component is receiving redirect-on-submit="false" but really I'm not passing any props to it. Commented Oct 26, 2021 at 20:30

2 Answers 2

18

Vue defaults Boolean props to false if no default was specified in the prop declaration. The author of Vue explains the reasoning:

The boolean casting follows the same rule of a boolean attribute: presence of any value are casted to true, absence means false.

To default the props to true, declare the prop with a default option of true, using the object-based syntax for the prop declaration, as seen in this Options API example:

<script>
export default {
  props: {
    myOptionalBool: {
      type: Boolean,
      default: true, 👈
    }
  }
}
</script>

Option 1: defineProps(props)

In <script setup>, defineProps() accepts the prop declaration object (shown above) as a function argument. Since defineProps() only accepts either the function argument or the generic type argument, all props would have to be declared in the function argument:

<script lang="ts" setup>
const props = defineProps({
  message: String,
  showRegisterLink: {
    type: Boolean,
    default: true,
  },
  redirectOnSubmit: {
    type: Boolean,
    default: true,
  },
})
</script>

demo 1

Option 2: withDefaults() and defineProps<T>()

The withDefaults() macro can be used with defineProps<T>() to specify default values for specific props:

<script lang="ts" setup>
interface Props {
  message?: string
  redirectOnSubmit?: boolean
  showRegisterLink?: boolean
}
const props = withDefaults(defineProps<Props>(), {
  redirectOnSubmit: true,
  showRegisterLink: true,
})
</script>

demo 2

Sign up to request clarification or add additional context in comments.

2 Comments

How Vue treats boolean props is still a weird part of Vue's API, and is inconsistent with HTML, JS, TS, and Vue itself. See: github.com/vuejs/vue/issues/4792#issuecomment-1591765678
thank you so much, why tf is so hard to find this explanation in vue docs ????
7

To answer the question more explicitly:

You must use withDefaults and explicitly pass undefined as the default:

const props = withDefaults(defineProps<{
  message?: string;
  redirectOnSubmit?: boolean;
  showRegisterLink?: boolean;
}>(), {
  redirectOnSubmit: undefined,
  showRegisterLink: undefined
})

This forces the optional boolean attributes to be undefined instead of false when not passed.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.