Skip to content

Creating a component in a generic function with props of those generic types causes compiler error #61

@6XGate

Description

@6XGate

Creating a component constructor from a generic function that has any properties of those types will not compile in markup. It produces the following compiler error based on the provided example:

${projectDir}/render/app/components/test.tsx:54:36: No overload matches this call.
  Overload 1 of 3, '(options?: ThisTypedComponentOptionsWithArrayProps<{ _tsxattrs: TsxComponentAttrs<{ options: T[]; } & { value?: V | undefined; }, {}, {}>; } & Vue & { innerValue: number | undefined; } & { onChange(value: number): void; } & { ...; } & { ...; }, object, object, object, never> | undefined): CombinedVueInstance<...>', gave the following error.
    Type '{ label: string; value: number; }[]' is not assignable to type 'T[]'.
      Type '{ label: string; value: number; }' is not assignable to type 'T'.
        'T' could be instantiated with an arbitrary type which could be unrelated to '{ label: string; value: number; }'.
  Overload 2 of 3, '(options?: ThisTypedComponentOptionsWithRecordProps<{ _tsxattrs: TsxComponentAttrs<{ options: T[]; } & { value?: V | undefined; }, {}, {}>; } & Vue & { innerValue: number | undefined; } & { onChange(value: number): void; } & { ...; } & { ...; }, object, object, object, object> | undefined): CombinedVueInstance<...>', gave the following error.
    Type '{ label: string; value: number; }[]' is not assignable to type 'T[]'.
  Overload 3 of 3, '(options?: ComponentOptions<{ _tsxattrs: TsxComponentAttrs<{ options: T[]; } & { value?: V | undefined; }, {}, {}>; } & Vue & { innerValue: number | undefined; } & { onChange(value: number): void; } & { ...; } & { ...; }, ... 4 more ..., Record<...>> | undefined): CombinedVueInstance<...>', gave the following error.
    Type '{ label: string; value: number; }[]' is not assignable to type 'T[]'. [TS2769]

Example:

import { PropOptions, PropType, VNode } from "vue";
import * as tsx from "vue-tsx-support";

const options = [
    { label: "Option One", value: 1 },
    { label: "Option Two", value: 2 },
    { label: "Option Three", value: 3 },
];

type Option = typeof options[number];

function select<T, V extends number|string>(predicate: (option: T) => [ string, V ]) {
    return tsx.component({
        name:  "Select",
        props: {
            value:   { default: undefined } as PropOptions<V>,
            options: { type: Array as PropType<T[]>, required: true },
        },
        data: function () {
            return {
                innerValue: this.value as V|undefined,
            };
        },
        computed: {
            label(): string {
                const value = this.options.find(option => predicate(option)[1] === this.innerValue);

                return value ? predicate(value)[0] : "Required";
            },
        },
        methods: {
            onChange(value: V) {
                this.innerValue = value;
                this.$emit("change", value);
            },
        },
        render(): VNode {
            return (<select value={this.innerValue} onChange={value => this.onChange(value as any)}>{
                this.options.map(option => (
                    <option value={predicate(option)[1]}>{predicate(option)[0]}</option>
                ))
            }</select>);
        },
    });
}

// OptionSelect is typeof Select<Option, number>;
const OptionSelect = select((option: Option) => [ option.label, option.value ]);

// @vue/component
const test = tsx.component({
    name: "test",
    render(): VNode {
        return (<div><OptionSelect options={options}/></div>);
    },
});

type test = InstanceType<typeof test>;
export default test;

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions