11

As an exercise, I'm trying to define the FontAwesome Vue implementation in TypeScript. They allow the icon prop to have different types:

icon: {
    type: [Object, Array, String],
    required: true
},

I tried to add a validation to it, but then props in setup seems broken:

validator: (prop) => {
    if (typeof prop === 'object') {
        const obj = prop as any;
        return (obj.prefix && obj.iconName);
    } else if (Array.isArray(prop) && prop.length === 2) {
        return true;
    }
    return typeof prop === 'string';
}
Property 'icon' does not exist on type 'Readonly<{ [x: number]: string; } & { length?: number | undefined; toString?: string | undefined; toLocaleString?: string | undefined; concat?: string[] | undefined; join?: string | undefined; slice?: string[] | undefined; ... 16 more ...; flat?: unknown[] | undefined; }> | Readonly<...>'.
Property 'icon' does not exist on type 'Readonly<{ [x: number]: string; } & { length?: number | undefined; toString?: string | undefined; toLocaleString?: string | undefined; concat?: string[] | undefined; join?: string | undefined; slice?: string[] | undefined; ... 16 more ...; flat?: unknown[] | undefined; }>'.Vetur(2339)

Without the validator, I can do this in the setup:

setup(props) {
    let icon: Icon; // simple interface I defined having prefix and iconName
    if (typeof props.icon === 'object') {
        icon = props.icon as Icon;
    } else if (Array.isArray(props.icon) && props.icon.length === 2) {
        icon = {
            prefix: props.icon[0],
            iconName: props.icon[1],
        };
    } else if (typeof props.icon === 'string') {
        icon = {
            prefix: 'l',
            iconName: props.icon as string,
        };
    }
}

Any ideas on how I could make the validation work with this setup? or is there a better way to define a prop with multiple types?

1

2 Answers 2

35

From how I understand the docs something like the following would be needed:

import { defineComponent, PropType } from 'vue'

interface Icon {
  src: string
  width: number
  height: number
}

const Component = defineComponent({
  props: {
    icon: {
        type: [Object, Array, String] as PropType<Icon | Icon[] | string>,
        required: true
    },
  }
})
Sign up to request clarification or add additional context in comments.

1 Comment

Likewise for the data property. For example: data(){ id: null as number | null}
0

You can cast it to the type.

{
    name: 'Bob' as string | number,
}

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.