Skip to content

TypeScript's defineProps macro does not properly map to the object version in the case of booleans #8576

@matthew-dean

Description

@matthew-dean

What problem does this feature solve?

Vue has an unexpected behavior where if you do this:

props: {
  foo: {
    type: Boolean,
    required: false
  }
}

...the value of foo, if not specified, will be false instead of undefined. This is somewhat unexpected, as noted in vuejs/vue#7646 and vuejs/vue#4792, but my guess is that this was a conscious choice by Vue to imitate the behavior certain HTML values, at least their values in the DOM.

The problem comes in the TypeScript extension of Vue. Say you have this:

<script setup lang="ts">
interface Props {
  foo?: boolean
}
defineProps<Props>()
</script>

TypeScript is very clear about interface syntax, which is that foo?: boolean means that the value of foo will be undefined if it is not specified. The type, in fact, is not boolean but boolean | undefined from TypeScript's perspective.

Meaning, the most accurate translation of TypeScript to Vue's JavaScript API when passing an interface would be:

props: {
  foo: {
    type: Boolean,
    required: false,
    default: undefined
  }
}

I would consider this a bug of not interpreting a TypeScript interface accurately, BUT it could be also considered a feature request as supporting optional properties in TypeScript, which may have not been fully implemented.

What does the proposed API look like?

Ideally, the API would be identical:

<script setup lang="ts">
interface Props {
  foo?: boolean
}
defineProps<Props>()
</script>

However, it's rational that there would be concern about breaking changes, so this is what I propose, which is a compile-time error vs a possible runtime change:

  1. If a TypeScript type is passed into withDefaults(defaultProps<Props>, {}), any boolean type should be required in the withDefaults object, so that the developer can make it clear if they are intending the default Vue behavior, or the default TypeScript behavior.
  2. Ideally, a withDefaults macro would be required with a defaultProps macro if, again, there are boolean types in the interface, but that could be considered too high of a burden for developers.

So, my proposal, at minimum, is that the provided script block throws an error (or I can set a TypeScript strictness check to throw an error?). Thanks for considering this.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions