Skip to content
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

Type () => boolean is not assignable type boolean when using withDefault with a factory function #7677

Closed
mrleblanc101 opened this issue Feb 9, 2023 · 6 comments
Labels
🐞 bug Something isn't working scope: types

Comments

@mrleblanc101
Copy link

mrleblanc101 commented Feb 9, 2023

Vue version

3.2.47

Link to minimal reproduction

.

Steps to reproduce

Type '() => boolean' is not assignable to type 'boolean | ((props: Readonly<Omit<Props, "expanded" | "hwAcceleration"> & { expanded: boolean; hwAcceleration: boolean; }>) => false) | ((props: Readonly<Omit<Props, "expanded" | "hwAcceleration"> & { ...; }>) => true) | undefined'.
Type '() => boolean' is not assignable to type '(props: Readonly<Omit<Props, "expanded" | "hwAcceleration"> & { expanded: boolean; hwAcceleration: boolean; }>) => false'.

Not sure why there is a type error on hwAcceleration but not duration if it's invalid.

export interface Props {
    expanded: boolean;
    duration?: number;
    hwAcceleration?: boolean;
}

const props = withDefaults(defineProps<Props>(), {
    expanded: false,
    duration: () => inject<PluginOptions>(PLUGIN_KEY)?.duration || 300,
    hwAcceleration: () => inject<PluginOptions>(PLUGIN_KEY)?.hwAcceleration || false,
});

Changing the interface to this solve the type error, but it seems wrong.
The type of the value is still boolean, the fact that Vue need a factory function in withDefaults doesn't change the nature of the value, is this a bug with withDefaults ?

export interface Props {
    expanded: boolean;
    duration?: () => number;
    hwAcceleration?: () => boolean;
}

What is expected?

It shouldn't be required from the Vue documentation.
Reference: https://vuejs.org/api/sfc-script-setup.html#default-props-values-when-using-type-declaration.

export interface Props {
  msg?: string
  labels?: string[]
}

const props = withDefaults(defineProps<Props>(), {
  msg: 'hello',
  labels: () => ['one', 'two']
})

What is actually happening?

Type '() => boolean' is not assignable to type 'boolean | ((props: Readonly<Omit<Props, "expanded" | "hwAcceleration"> & { expanded: boolean; hwAcceleration: boolean; }>) => false) | ((props: Readonly<Omit<Props, "expanded" | "hwAcceleration"> & { ...; }>) => true) | undefined'.
Type '() => boolean' is not assignable to type '(props: Readonly<Omit<Props, "expanded" | "hwAcceleration"> & { expanded: boolean; hwAcceleration: boolean; }>) => false'.

System Info

No response

Any additional comments?

No response

@mrleblanc101 mrleblanc101 changed the title Type () => boolean is not assignable type boolean Type () => boolean is not assignable type boolean when using withDefault with a factory function Feb 9, 2023
@mrleblanc101
Copy link
Author

If I add a // @ts-ignore and check the built code.
I see this, which seems perfectly fine.

{
  expanded: { type: Boolean, required: !0, default: !1 },
  duration: {
    type: Number,
    required: !1,
    default: () => {
      var e;
      return ((e = i(s)) == null ? void 0 : e.duration) || 300;
    },
  },
  hwAcceleration: {
    type: Boolean,
    required: !1,
    default: () => {
      var e;
      return ((e = i(s)) == null ? void 0 : e.hwAcceleration) || !1;
    },
  },
}

@mrleblanc101
Copy link
Author

@LinusBorg @yyx990803 How are pending PR reviewed/managed ? Any chance that this will get merged with 3.3 ?

@mrleblanc101
Copy link
Author

@LinusBorg @yyx990803
Sorry to ping again, but any idea when this could get merged ? I would be sad to have to wait another 2 years like we did between 3.2 and 3.3

@nborko
Copy link

nborko commented Aug 22, 2023

EDIT: I just realized that the withDefaults macro is documents to remove undefined from the defaulted props; however, in my use case the function used for the default value can return a value OR undefined, depending on circumstances, where undefined is a perfectly valid value meaning "unused". Perhaps withDefaults is just not appropriate for this use case? Original comment follows:

I don't know if this is related, but if a prop is optional, returning undefined from a function also triggers a type error, even though doing the same in the options API is fine (and the only way to positively assign undefined as the default value).

e.g., given:

interface Props {
   opt?: string
}

Then:

const props: Props = defineProps({
  opt: String,
  required: false,
  default: () => undefined
})

works fine, but:

const props = withDefaults(defineProps<Props>(), {
  opt: () => undefined
})

causes a type error:

Type '() => undefined' is not assignable to type 'InferDefault<Props, string | undefined> | undefined'.
  Type '() => undefined' is not assignable to type '(props: Props) => string'.ts(2322)

@mrleblanc101
Copy link
Author

@nborko Well, in your first exemple the opt props is optional opt?: string. But in your second the props is not (you ommited the ?).
You code should be this:

const props = withDefaults(defineProps<Props>(), {
  opt?: () => undefined
})

@pikax
Copy link
Member

pikax commented Oct 25, 2023

Closing this issue since it's working on the latest version, playground

image

@pikax pikax closed this as completed Oct 25, 2023
@github-actions github-actions bot locked and limited conversation to collaborators Nov 9, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
🐞 bug Something isn't working scope: types
Projects
None yet
4 participants