babel-plugin-jsx
babel-plugin-jsx copied to clipboard
jsx onClick is not assignable to type of .vue (custom component)
VButton
<script setup lang="ts">
import { computed } from "vue";
interface Props {
theme?: string;
size?: string;
level?: string;
disabled?: boolean;
loading?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
theme: "button",
size: "normal",
level: "normal",
disabled: false,
loading: false,
});
const classes = computed(() => {
return {
[`v3-theme-${props.theme}`]: props.theme,
[`v3-size-${props.size}`]: props.size,
[`v3-level-${props.level}`]: props.level,
};
});
</script>
<template>
<button class="v3-button" :class="classes" :disabled="props.disabled">
<span v-if="props.loading" class="v3-loading-indicator"></span>
<span v-else class="v3-loading-indicator-empty"></span>
<slot />
</button>
</template>
use VButton
export const DemoX = defineComponent({
props: {
component: {
type: Object as PropType<Component>,
required: true,
},
},
setup(props, { attrs, slots, emit, expose }) {
// 渲染源码
const html = computed(() => {
return Prism.highlight(
(props.component as ComponentType).__sourceCode,
Prism.languages.html,
"html"
);
});
// 源码是否可见
const codeVisible = ref(false);
const toggleCodeVisible = () =>
(codeVisible.value = !codeVisible.value);
return () => (
<div class={style.container}>
<h2>{(props.component as ComponentType).__sourceCodeTitle}</h2>
<div class={style.component}>{h(props.component)}</div>
<div class={style.action}>
<VButton onClick={withModifiers(toggleCodeVisible, ["self"])}>
{codeVisible.value ? "隐藏源代码" : "查看源代码"}
</VButton>
</div>
{codeVisible.value ? (
<div class={style.code}>
<pre class={"language-html"} innerHTML={html.value} />
</div>
) : (
<div />
)}
</div>
);
},
});
Question
It works normally when I use yarn dev, but it will report error when I use vue-tsc --noEmit && vite build
error TS2322: Type '{ onClick: (event: Event, ...args: unknown[]) => any; }' is not assignable to type 'IntrinsicAttributes & Partial<{ loading: boolean; disabled: boolean; size: string; theme: string; level: string; }> & Omit<Readonly<ExtractPropTypes<{ theme: { type: PropType<string>; } & { ...; }; size: { ...; } & { ...; }; level: { ...; } & { ...; }; disabled: { ...; } & { ...; }; loading: { ...; } & { ...; }; }>>...'.
Property 'onClick' does not exist on type 'IntrinsicAttributes & Partial<{ loading: boolean; disabled: boolean; size: string; theme: string; level: string; }> & Omit<Readonly<ExtractPropTypes<{ theme: { type: PropType<string>; } & { ...; }; size: { ...; } & { ...; }; level: { ...; } & { ...; }; disabled: { ...; } & { ...; }; loading: { ...; } & { ...; }; }>>...'.
56 <VButton onClick={withModifiers(toggleCodeVisible, ["self"])}>
~~~~~~~
error Command failed with exit code 2.
I temporarily avoided this problem by wrapping a layer of div and setting the click event to the div.
<div onClick={withModifiers(toggleCodeVisible, ["stop"])}>
<VButton>
{codeVisible.value ? "隐藏源代码" : "查看源代码"}
</VButton>
</div>
Should I add an onClick prop to the VButton to solve this problem more rationally?
@icuxika here is component example. Hope it will help you. If you have any questions, you are free to ask. 🙃
@icuxika, you did not provide $attrs
<template>
<button class="v3-button" :class="classes" :disabled="props.disabled" v-bind="$attrs">
<span v-if="props.loading" class="v3-loading-indicator"></span>
<span v-else class="v3-loading-indicator-empty"></span>
<slot />
</button>
</template>
Also I dont know if .tsx file will catch all component types that come from .vue component.
@funny-family Thanks, As a component in the library, I directly used this button by import the .vue and encountered this problem. Today I saw your new answer and try to delete the div, but there are some changes, which I didn't import
@icuxika, I still recommend you to take a lot at example of component. And yes, as you mentioned, vue3 and jsx have "some details", but in reality it has "a lot" of details.
Always glad to help 🙂
@icuxika Thank you for your advice. I will try to learn everything about example.
Type '{ onClick: () => boolean; }' is not assignable to type 'IntrinsicAttributes & Partial ...
Manually adding HTMLAttributes to merge into Props is a bit burdensome. It requires a lot of boilerplate code to satisfy a basic need.
Using v-bind="$attrs" is not working. I add defineEmits(['click']); and <button @click="$emit('click')" /> as a temporary workaround. (although it is not a good one)
Looking forward to future updates.
@mockingjet I avoided this by using the global registration of the Vue component, but the TypeScript attribute hint for
https://github.com/icuxika/vue-scaffold-ui/blob/main/src/main.ts
import {
create as createVUI,
VBanner,
VButton,
VMarkdown,
VVerification,
VConfigProvider,
} from "@icuxika/vue-scaffold-ui";
const vueScaffoldUI = createVUI({
components: [VBanner, VButton, VMarkdown, VVerification, VConfigProvider],
});
https://github.com/icuxika/vue-scaffold-ui/blob/main/lib/create.ts
const create = ({
components = [],
componentPrefix = "V",
}: VCreateOption): VInstance => {
const registerComponent = (
app: App,
name: string,
component: Component
) => {
const registered = app.component(componentPrefix + name);
if (!registered) {
app.component(componentPrefix + name, component);
}
};
const install = (app: App) => {
components.forEach((component) => {
registerComponent(app, component.name ?? "", component);
});
};
return {
install,
};
};
https://github.com/icuxika/vue-scaffold-ui/blob/main/lib/button/Button.vue
<template>
<button class="v3-button" :class="classes" :disabled="props.disabled">
<span v-if="props.loading" class="v3-loading-indicator"></span>
<span v-else class="v3-loading-indicator-empty"></span>
<slot />
</button>
</template>
https://github.com/icuxika/vue-scaffold-ui/blob/main/src/views/components/DemoX.tsx
return () => (
<div class={style.container}>
<h2>{(props.component as ComponentType).__sourceCodeTitle}</h2>
<div class={style.component}>{h(props.component)}</div>
<div class={style.action}>
<v-button
onClick={withModifiers(toggleCodeVisible, ["stop"])}
>
{codeVisible.value ? "隐藏源代码" : "查看源代码"}
</v-button>
</div>
{codeVisible.value ? (
<div class={style.code}>
<pre class={"language-html"} innerHTML={html.value} />
</div>
) : (
<div />
)}
</div>
);