How to set default value on complex prop using Vue's Type-based props declarations

183 Views Asked by At

I can't get around this error:

Argument of type 'HelloWorldProps' is not assignable to parameter of type 'InferDefaults<LooseRequired<HelloWorldProps>>'.
  Types of property 'complexProp' are incompatible.ts(2345)

Code:

<script lang="ts">
export type ComplextPropType = boolean | string | any[] | null;

export interface HelloWorldProps {
  simpleProp?: boolean;
  complexProp: ComplextPropType;
  labels?: string[] // Vue docs example
}

export const HelloWorldPropsDefaults: HelloWorldProps = {
  simpleProp: false,
  complexProp: ((): ComplextPropType => null)(),
  //complexProp: ((): ComplextPropType => null),
  //complexProp: null,
  //labels: ()=> ['a', 'b'] // Vue docs mention something like this
};
</script>
<script setup lang="ts">
const props = withDefaults(
  defineProps<HelloWorldProps>(),
  HelloWorldPropsDefaults, // <-- Error reported here
);
</script>
<template>
  <h1>{{ props.complexProp }}</h1>
</template>

How would I default the complexProp?

1

There are 1 best solutions below

0
On

The default values should be provided inline since this gives a good inference :

const props = withDefaults(
  defineProps<HelloWorldProps>(),
   {
     simpleProp: false,
     complexProp: ()=>[],
   }
);

But if you prefer to separate them as I had already done, you should define some type utilities like those that I copied from the vue runtime core :

<script lang="ts">
// you could put them in another file and use them across your app
type NotUndefined<T> = T extends undefined ? never : T

export type NativeType = null | number | string | boolean | symbol

type InferDefault<P, T> =

    ((props: P) => T & {}) | (T extends NativeType ? T : never) | (T extends (...args: any[]) => any ? T : never)

export type InferDefaults<T> = {
    [K in keyof T]?: InferDefault<T, T[K]>
}

export type ComplextPropType = boolean | string | any[] | null;

export interface HelloWorldProps {
  simpleProp?: boolean;
  complexProp: ComplextPropType;
  labels?: string[]
}

export const HelloWorldPropsDefaults: InferDefaults<HelloWorldProps> = {
  simpleProp: false,
  complexProp: ()=>[],
};

</script>

<script setup lang="ts">
const props = withDefaults(
  defineProps<HelloWorldProps>(),
  HelloWorldPropsDefaults, 
);
</script>
<template>
  <h1>{{ props.complexProp }}</h1>
</template>