Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## Unreleased

### Fixes

- Fixed TypeScript declaration generation for libraries that re-export or wrap Vue ECharts components. The public type exports are `Component`, `Exposed`, and `Slots`; `Exposed` includes all exposed chart methods and read-only state.

## 8.3.0

### Improvements
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,10 @@ const chart = ref<InstanceType<typeof VChart> | null>(null);

Vue 3.5's `useTemplateRef` can infer this type automatically.

`Exposed` describes the chart methods and read-only `chart` and `root` properties exposed through a template ref. It includes `setOption` and the other methods listed below; use `InstanceType<typeof VChart>` when you also need Vue's component instance properties.

Libraries can re-export or wrap `VChart` and the `vue-echarts/graphic` components while emitting their own TypeScript declarations. The root entry exports `Component`, the shared Vue component definition helper, and `Slots`, the Vue `SlotsType` metadata used by `VChart`, so inferred declarations can reference public types. The graphic entry exports its corresponding `GraphicComponent` type. For callable slots, use `InstanceType<typeof VChart>["$slots"]`; augment `VChartSlotsExtension` in `vue-echarts` to declare additional slots. The graphic entry re-exports the same extension interface.

### Events

You can bind events with Vue's `v-on` directive.
Expand Down
4 changes: 4 additions & 0 deletions README.zh-Hans.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ const chart = ref<InstanceType<typeof VChart> | null>(null);

Vue 3.5 的 `useTemplateRef` 可以自动推导此类型。

`Exposed` 描述通过模板 ref 暴露的图表方法及只读的 `chart`、`root` 属性,包含 `setOption` 和下文列出的其它方法。如果还需要 Vue 组件实例属性,请使用 `InstanceType<typeof VChart>`。

组件库可以重新导出或包装 `VChart` 及 `vue-echarts/graphic` 组件,并生成自己的 TypeScript 声明。根入口导出共享的 Vue 组件定义辅助类型 `Component` 和 `VChart` 使用的 Vue `SlotsType` 元数据 `Slots`,使推导出的声明能够引用公开类型。graphic 入口导出对应的 `GraphicComponent` 类型。需要可调用的插槽类型时,使用 `InstanceType<typeof VChart>["$slots"]`;需要声明额外插槽时,在 `vue-echarts` 模块中扩展 `VChartSlotsExtension`。graphic 入口重新导出的是同一个扩展接口。

### 事件

可以使用 Vue 的 `v-on` 指令绑定事件。
Expand Down
5 changes: 5 additions & 0 deletions package-tests/consumer-declaration-emit.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import ECharts from "vue-echarts";
import { GGroup, GRect } from "vue-echarts/graphic";

// Simulates a library that re-exports the component and emits its own `.d.ts`.
// Fails with TS4023 / TS2742 if the component type reaches a name no entry point exports.
Expand All @@ -7,3 +8,7 @@ export const ReExportedChart = ECharts;
export const WrappedChart = {
component: ECharts,
} as const;

// Graphic components share the component definition helper with the root entry.
export const ReExportedGroup = GGroup;
export const WrappedGraphic = { component: GRect } as const;
51 changes: 51 additions & 0 deletions package-tests/public-component-types.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import VChart, {
type Component,
type Exposed,
type VChartSlotsExtension,
type Slots,
} from "vue-echarts";
import type { VChartSlotsExtension as GraphicSlotsExtension } from "vue-echarts/graphic";
import type { SlotsType as VueSlotsType } from "vue";
import type { EChartsType } from "echarts/core";

declare module "vue-echarts" {
interface VChartSlotsExtension {
custom?: (props: { value: number }) => unknown;
}
}

type Assert<T extends true> = T;
type IsEqual<A, B> =
(<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;
type Instance = InstanceType<typeof VChart>;
type InstanceSlots = Instance["$slots"];

export type ExposedMatchesInstance = Assert<
IsEqual<Pick<Instance, keyof Exposed>, { [K in keyof Exposed]: Exposed[K] }>
>;
export type ExposedIncludesSetOption = Assert<
IsEqual<Exposed["setOption"], EChartsType["setOption"]>
>;
export type ExposedPreservesZRender = Assert<IsEqual<Exposed["getZr"], EChartsType["getZr"]>>;
export type ExposedStateIsReadonly = Assert<
IsEqual<Pick<Exposed, "chart" | "root">, Readonly<Pick<Exposed, "chart" | "root">>>
>;
export type CustomSlotProps = Assert<
IsEqual<Parameters<NonNullable<InstanceSlots["custom"]>>[0], { value: number }>
>;
export type GraphicSlotIsPreserved = Assert<"graphic" extends keyof InstanceSlots ? true : false>;
export type GraphicUsesSameExtension = Assert<IsEqual<GraphicSlotsExtension, VChartSlotsExtension>>;
export type SlotMetadataIsPreserved = Assert<
Slots extends VueSlotsType<VChartSlotsExtension> ? true : false
>;
export type InferredPropsArePreserved = Assert<
IsEqual<Instance["$props"]["manualUpdate"], boolean | undefined>
>;

// All exported names remain usable in consumers that emit their own declarations.
export type WrapperComponent = Component<
Record<never, never>,
Exposed,
Record<never, never>,
Slots
>;
11 changes: 6 additions & 5 deletions src/ECharts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import type { InjectionKey, PropType, VNodeChild } from "vue";
import { usePublicAPI, type PublicMethods } from "./composables/api";
import { useAutoresize, autoresizeProps } from "./composables/autoresize";
import { useLoading, loadingProps } from "./composables/loading";
import { useSlotOption, type SlotsTypes } from "./composables/slot";
import { useSlotOption, type Slots } from "./composables/slot";
import { hasZeroDimension, isIgnorableWatchChange, warn } from "./utils";
import { register, TAG_NAME } from "./wc";
import { useRuntime as useGraphic } from "./graphic/runtime";
Expand All @@ -38,7 +38,7 @@ import type {
UpdateOptions,
UpdateOptionsInjection,
Emits,
PublicComponent,
Component,
} from "./types";
import type { EChartsElement } from "./wc";

Expand Down Expand Up @@ -72,7 +72,8 @@ const chartProps = {
...loadingProps,
};

type Bindings = {
/** Methods and read-only state exposed by VChart through a template ref. */
export type Exposed = {
setOption: SetOptionType;
readonly root: HTMLElement | undefined;
readonly chart: EChartsType | undefined;
Expand All @@ -83,7 +84,7 @@ const ECharts = /* @__PURE__ */ defineComponent({
inheritAttrs: false,
props: chartProps,
emits: {} as Emits,
slots: Object as SlotsTypes,
slots: Object as Slots,
setup(props, { attrs, expose, slots }) {
const root = shallowRef<EChartsElement>();
const chartHost = shallowRef<HTMLDivElement>();
Expand Down Expand Up @@ -533,6 +534,6 @@ const ECharts = /* @__PURE__ */ defineComponent({
);
}) as unknown as typeof exposed & PublicMethods;
},
}) as PublicComponent<typeof chartProps, Bindings, Emits, SlotsTypes>;
}) as Component<typeof chartProps, Exposed, Emits, Slots>;

export default ECharts;
7 changes: 4 additions & 3 deletions src/composables/slot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
shallowRef,
shallowReactive,
} from "vue";
import type { Slots, SlotsType } from "vue";
import type { Slots as VueSlots, SlotsType as VueSlotsType } from "vue";
import type { Option } from "../types";
import { isPlainObject, isValidArrayIndex, warn } from "../utils";
import type { TooltipComponentFormatterCallbackParams } from "echarts";
Expand Down Expand Up @@ -110,7 +110,7 @@ function writePath(
return true;
}

export function useSlotOption(slots: Slots, onSlotsChange: () => void) {
export function useSlotOption(slots: VueSlots, onSlotsChange: () => void) {
const instance = getCurrentInstance()!;
let detachedRoot: HTMLDivElement | undefined;
const containers = shallowReactive<SlotMap<HTMLElement>>({});
Expand Down Expand Up @@ -275,7 +275,8 @@ export function useSlotOption(slots: Slots, onSlotsChange: () => void) {
};
}

export type SlotsTypes = SlotsType<
/** Vue SlotsType metadata for VChart, including VChartSlotsExtension augmentations. */
export type Slots = VueSlotsType<
Record<"tooltip" | `tooltip-${string}`, TooltipComponentFormatterCallbackParams> &
Record<"dataView" | `dataView-${string}`, Option> &
VChartSlotsExtension
Expand Down
4 changes: 2 additions & 2 deletions src/graphic/component-factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
watch,
} from "vue";

import type { PublicComponent } from "../types";
import type { Component } from "../types";
import { warn } from "../utils";
import { GRAPHIC_COLLECTOR_KEY, GRAPHIC_PARENT_ID_KEY } from "./context";
import { resolveIdentity } from "./identity";
Expand Down Expand Up @@ -201,7 +201,7 @@ export function createComponent<T extends GraphicComponentType>(
}) as GraphicComponent<T>;
}

export type GraphicComponent<T extends GraphicComponentType> = PublicComponent<
export type GraphicComponent<T extends GraphicComponentType> = Component<
ComponentProps<T>,
Record<never, never>,
GraphicEmits,
Expand Down
1 change: 1 addition & 0 deletions src/graphic/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { registerExtension } from "./extension";
registerExtension();

export type { VChartSlotsExtension } from "../index";
export type { GraphicComponent } from "./component-factory";
export type { GraphicEmits, GraphicEventName, GraphicOnEventName } from "./types";
export type { GraphicCommonProps } from "./props-common";
export type { GraphicShapeProps } from "./props-shape";
Expand Down
5 changes: 2 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,5 @@ export interface VChartSlotsExtension {

export default ECharts;
export * from "./ECharts";
export type { AutoResize, LoadingOptions, PublicComponent } from "./types";
export type { PublicMethods } from "./composables/api";
export type { SlotsTypes } from "./composables/slot";
export type { AutoResize, LoadingOptions, Component } from "./types";
export type { Slots } from "./composables/slot";
3 changes: 2 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ type EventProps<T> = {
: never;
};

/** Shared component definition for VChart and graphic components across supported Vue versions. */
// The first 13 DefineComponent parameters are stable across the supported Vue versions.
export type PublicComponent<
export type Component<
Props extends ComponentPropsOptions,
Bindings,
Events extends EmitsOptions,
Expand Down
Loading