refactor: switch to generated .d.ts (#835)

* build: generate d.ts

* fix: preserve PublicMethods

* fix: avoid exposing types of attrs

* refactor: use existing setoption type

* fix: expose root and chart

* feat: use symbol as injection key

* chore: add comment for the type casting of the exposed
This commit is contained in:
Yue JIN
2025-06-01 12:29:26 +08:00
committed by GitHub
parent 8be19fe2a5
commit f7ed1e1b7d
9 changed files with 229 additions and 613 deletions

View File

@ -11,7 +11,7 @@
"scripts": {
"dev": "vite",
"build": "pnpm run docs && rimraf dist && rollup -c",
"typecheck": "vue-tsc",
"typecheck": "tsc",
"lint": "eslint . --fix",
"format": "prettier . --write",
"publint": "publint",
@ -41,7 +41,7 @@
},
"devDependencies": {
"@highlightjs/vue-plugin": "^2.1.0",
"@rollup/plugin-replace": "^5.0.7",
"@rollup/plugin-replace": "^6.0.2",
"@types/node": "^22.15.21",
"@typescript-eslint/utils": "^8.32.1",
"@vercel/analytics": "^1.3.1",
@ -64,10 +64,10 @@
"prettier": "^3.5.3",
"publint": "^0.3.12",
"rimraf": "^6.0.1",
"rollup": "^4.19.0",
"rollup-plugin-dts": "^6.1.0",
"rollup-plugin-esbuild": "^6.1.1",
"rollup-plugin-import-css": "^3.5.1",
"rollup": "^4.41.1",
"rollup-plugin-dts": "^6.2.1",
"rollup-plugin-esbuild": "^6.2.1",
"rollup-plugin-import-css": "^3.5.8",
"typescript": "^5.8.3",
"vite": "^6.3.5",
"vue": "^3.5.13",

658
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@ import replace from "@rollup/plugin-replace";
import esbuild from "rollup-plugin-esbuild";
import { dts } from "rollup-plugin-dts";
import css from "rollup-plugin-import-css";
import { defineConfig } from "rollup";
/**
* Modifies the Rollup options for a build to support strict CSP
@ -73,12 +74,24 @@ const builds = [
},
];
export default [
export default defineConfig([
...builds.map((options) => configBuild(options, false)),
...builds.map((options) => configBuild(options, true)),
{
input: "src/index.d.ts",
plugins: [dts()],
input: "src/index.ts",
plugins: [
dts({
// https://github.com/unjs/unbuild/pull/57/files
compilerOptions: {
preserveSymlinks: false,
},
}),
{
load(id) {
if (id.endsWith(".css")) return "";
},
},
],
output: [
{
file: "dist/index.d.ts",
@ -90,4 +103,4 @@ export default [
},
],
},
];
]);

View File

@ -19,6 +19,7 @@ import {
autoresizeProps,
useLoading,
loadingProps,
type PublicMethods,
} from "./composables";
import { isOn, omitOn, toValue } from "./utils";
import { register, TAG_NAME } from "./wc";
@ -26,6 +27,7 @@ import { register, TAG_NAME } from "./wc";
import type { PropType, InjectionKey } from "vue";
import type {
EChartsType,
SetOptionType,
Option,
Theme,
ThemeInjection,
@ -42,11 +44,10 @@ import "./style.css";
const __CSP__ = false;
const wcRegistered = __CSP__ ? false : register();
export const THEME_KEY = "ecTheme" as unknown as InjectionKey<ThemeInjection>;
export const INIT_OPTIONS_KEY =
"ecInitOptions" as unknown as InjectionKey<InitOptionsInjection>;
export const UPDATE_OPTIONS_KEY =
"ecUpdateOptions" as unknown as InjectionKey<UpdateOptionsInjection>;
export const THEME_KEY: InjectionKey<ThemeInjection> = Symbol();
export const INIT_OPTIONS_KEY: InjectionKey<InitOptionsInjection> = Symbol();
export const UPDATE_OPTIONS_KEY: InjectionKey<UpdateOptionsInjection> =
Symbol();
export { LOADING_OPTIONS_KEY } from "./composables";
export default defineComponent({
@ -65,7 +66,7 @@ export default defineComponent({
},
emits: {} as unknown as Emits,
inheritAttrs: false,
setup(props, { attrs }) {
setup(props, { attrs, expose }) {
const root = shallowRef<EChartsElement>();
const chart = shallowRef<EChartsType>();
const manualOption = shallowRef<Option>();
@ -189,8 +190,14 @@ export default defineComponent({
commit();
}
}
const setOption: SetOptionType = (
option,
notMerge,
lazyUpdate?: boolean,
) => {
const updateOptions =
typeof notMerge === "boolean" ? { notMerge, lazyUpdate } : notMerge;
function setOption(option: Option, updateOptions?: UpdateOptions) {
if (props.manualUpdate) {
manualOption.value = option;
}
@ -200,7 +207,7 @@ export default defineComponent({
} else {
chart.value.setOption(option, updateOptions || {});
}
}
};
function cleanup() {
if (chart.value) {
@ -284,21 +291,23 @@ export default defineComponent({
}
});
return {
chart,
root,
const exposed = {
setOption,
nonEventAttrs,
nativeListeners,
...publicApi,
root,
chart,
};
},
render() {
return h(TAG_NAME, {
...this.nonEventAttrs,
...this.nativeListeners,
ref: "root",
class: ["echarts", ...(this.nonEventAttrs.class || [])],
});
expose({ ...exposed, ...publicApi });
// While `expose()` exposes methods and properties to the parent component
// via template refs at runtime, it doesn't contribute to TypeScript types.
// This type casting ensures TypeScript correctly types the exposed members
// that will be available when using this component.
return (() =>
h(TAG_NAME, {
...nonEventAttrs.value,
...nativeListeners,
ref: root,
class: ["echarts", ...(nonEventAttrs.value.class || [])],
})) as unknown as typeof exposed & PublicMethods;
},
});

View File

@ -21,7 +21,7 @@ const METHOD_NAMES = [
type MethodName = (typeof METHOD_NAMES)[number];
type PublicMethods = Pick<EChartsType, MethodName>;
export type PublicMethods = Pick<EChartsType, MethodName>;
export function usePublicAPI(
chart: Ref<EChartsType | undefined>,

View File

@ -2,16 +2,18 @@ import { inject, computed, watchEffect } from "vue";
import { toValue } from "../utils";
import type { Ref, InjectionKey, PropType } from "vue";
import type { EChartsType, LoadingOptions } from "../types";
import type {
EChartsType,
LoadingOptions,
LoadingOptionsInjection,
} from "../types";
export const LOADING_OPTIONS_KEY =
"ecLoadingOptions" as unknown as InjectionKey<
LoadingOptions | Ref<LoadingOptions>
>;
export const LOADING_OPTIONS_KEY: InjectionKey<LoadingOptionsInjection> =
Symbol();
export function useLoading(
chart: Ref<EChartsType | undefined>,
loading: Ref<boolean>,
loading: Ref<boolean | undefined>,
loadingOptions: Ref<LoadingOptions | undefined>,
): void {
const defaultLoadingOptions = inject(LOADING_OPTIONS_KEY, {});

75
src/index.d.ts vendored
View File

@ -1,75 +0,0 @@
/* eslint-disable @typescript-eslint/no-empty-object-type */
import type { Ref, DefineComponent, InjectionKey } from "vue";
import type {
Option,
Theme,
InitOptions,
UpdateOptions,
LoadingOptions,
AutoResize,
EChartsType,
Emits,
ThemeInjection,
InitOptionsInjection,
UpdateOptionsInjection,
LoadingOptionsInjection,
} from "./types";
declare const THEME_KEY: InjectionKey<ThemeInjection>;
declare const INIT_OPTIONS_KEY: InjectionKey<InitOptionsInjection>;
declare const UPDATE_OPTIONS_KEY: InjectionKey<UpdateOptionsInjection>;
declare const LOADING_OPTIONS_KEY: InjectionKey<LoadingOptionsInjection>;
declare type ChartProps = {
theme?: Theme;
initOptions?: InitOptions;
updateOptions?: UpdateOptions;
loadingOptions?: LoadingOptions;
option?: Option;
autoresize?: AutoResize;
loading?: boolean;
group?: string;
manualUpdate?: boolean;
};
// convert Emits to Props
// click => onClick
declare type ChartEventProps = {
[key in keyof Emits as key extends string
? `on${Capitalize<key>}`
: never]?: Emits[key];
};
type MethodNames =
| "getWidth"
| "getHeight"
| "getDom"
| "getOption"
| "resize"
| "dispatchAction"
| "convertToPixel"
| "convertFromPixel"
| "containPixel"
| "getDataURL"
| "getConnectedDataURL"
| "appendData"
| "clear"
| "isDisposed"
| "dispose"
| "setOption";
declare type ChartMethods = Pick<EChartsType, MethodNames>;
declare const Chart: DefineComponent<
ChartProps & ChartEventProps,
{
root: Ref<HTMLElement | undefined>;
chart: Ref<EChartsType | undefined>;
},
{},
{},
ChartMethods
>;
export default Chart;
export { THEME_KEY, INIT_OPTIONS_KEY, UPDATE_OPTIONS_KEY, LOADING_OPTIONS_KEY };

View File

@ -19,15 +19,13 @@ export type InitParameters = Parameters<InitType>;
export type Theme = NonNullable<InitParameters[1]>;
export type ThemeInjection = Injection<Theme>;
export type InitOptions = NonNullable<InitParameters[2]>;
export type InitOptionsInjection = Injection<InitOptions>;
export type UpdateOptions = SetOptionOpts;
export type UpdateOptionsInjection = Injection<UpdateOptions>;
export type EChartsType = ReturnType<InitType>;
type SetOptionType = EChartsType["setOption"];
export type SetOptionType = EChartsType["setOption"];
export type Option = Parameters<SetOptionType>[0];
export type AutoResize =

View File

@ -1,12 +1,11 @@
{
"allowJs": true,
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"moduleResolution": "bundler",
"removeComments": true,
"skipLibCheck": true,
"esModuleInterop": true,