Skip to content

Optional properties not working in 0.40.5 when using exactOptionalProperties #1798

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
larrifax opened this issue Sep 1, 2022 · 3 comments
Closed
Labels
question Further information is requested

Comments

@larrifax
Copy link

larrifax commented Sep 1, 2022

I'm using "exactOptionalProperties": true in my tsconfig, and have been struggling with optional prop types.
After upgrading to 0.40.5 I simply can't get the following code to work, no matter the combination I choose for the type of the placeholder prop. I've tried the following combinations:

  • placeholder?: string | undefined (worked in <=0.40.4)
  • placeholder?: string (the proper type if you ask me)
  • placeholder: string | undefined
  • type Props = TextareaHTMLAttributes;
<template>
  <textarea :placeholder="placeholder" />
</template>

<script lang="ts" setup>
export type Props = { placeholder?: string | undefined };
const { placeholder } = defineProps<Props>();
</script>

The error message given for the above code is:

error TS2375: Type '{ placeholder: string | undefined; }' is not assignable to type 'ElementAttrs<TextareaHTMLAttributes>' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
  Type '{ placeholder: string | undefined; }' is not assignable to type 'TextareaHTMLAttributes' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
    Types of property 'placeholder' are incompatible.
      Type 'string | undefined' is not assignable to type 'string'.
        Type 'undefined' is not assignable to type 'string'.
@johnsoncodehk
Copy link
Member

johnsoncodehk commented Sep 4, 2022

Actually this is expected behavior, placeholder?: string is optional prop so it can be undefined in template.

You can reproduce this problem with equivalent regular ts code:

const Comp = defineComponent({
  props: {
    placeholder: {
      type: String,
      required: false,
    }
  }
});

const textarea: JSX.IntrinsicElements['textarea'] = {
  placeholder: (new Comp()).placeholder,
};

@johnsoncodehk johnsoncodehk added invalid This doesn't seem right question Further information is requested and removed bug Something isn't working invalid This doesn't seem right labels Sep 4, 2022
@larrifax
Copy link
Author

larrifax commented Sep 5, 2022

TL;DR: This might actually be a problem with @vue/runtime-dom

Yes, it's optional and should hence be undefined in the template.
But exactOptionalPropertyTypes makes Typescript discern "unset" from "undefined" (explicitly set).
So { anotherProp: "someValue" } != { anotherProp: "someValue", placeholder: undefined } in Typescripts eyes.

In my first post I attempted to set my optional placeholder prop to the <textarea> tag. Since the TextareaHTMLAttributes type associated with <textarea> contains { placeholder?: string }, Typescript won't allow undefined to be passed to the <textarea> tag, but the type of placeholder destructed from defineProps() is string | undefined, which causes Typescript to error.

If you look at a comparative React example on the Typescript playground, there's no error. Seems like they have amended the types of the placeholder prop on <textarea> to { placeholder?: string | undefined } which solves the problem.

So I guess the problem isn't Volars handling of this, but rather the types from @vue/runtime-dom..

@larrifax
Copy link
Author

larrifax commented Sep 5, 2022

BTW: 0.40.5 did actually solve optional props problems I was having with custom Vue components.
I can now set type Props = { someProp?: string } enabling consuming components to omit the prop entirely in their templates. Previously, this wasn't possible and forced me to use type Props = { someProp: string | undefined } and <SomeComp :someProps="undefined" /> at the consumer side.
Big thanks for that fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants