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": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "pnpm run docs && rimraf dist && rollup -c", "build": "pnpm run docs && rimraf dist && rollup -c",
"typecheck": "vue-tsc", "typecheck": "tsc",
"lint": "eslint . --fix", "lint": "eslint . --fix",
"format": "prettier . --write", "format": "prettier . --write",
"publint": "publint", "publint": "publint",
@ -41,7 +41,7 @@
}, },
"devDependencies": { "devDependencies": {
"@highlightjs/vue-plugin": "^2.1.0", "@highlightjs/vue-plugin": "^2.1.0",
"@rollup/plugin-replace": "^5.0.7", "@rollup/plugin-replace": "^6.0.2",
"@types/node": "^22.15.21", "@types/node": "^22.15.21",
"@typescript-eslint/utils": "^8.32.1", "@typescript-eslint/utils": "^8.32.1",
"@vercel/analytics": "^1.3.1", "@vercel/analytics": "^1.3.1",
@ -64,10 +64,10 @@
"prettier": "^3.5.3", "prettier": "^3.5.3",
"publint": "^0.3.12", "publint": "^0.3.12",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"rollup": "^4.19.0", "rollup": "^4.41.1",
"rollup-plugin-dts": "^6.1.0", "rollup-plugin-dts": "^6.2.1",
"rollup-plugin-esbuild": "^6.1.1", "rollup-plugin-esbuild": "^6.2.1",
"rollup-plugin-import-css": "^3.5.1", "rollup-plugin-import-css": "^3.5.8",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"vite": "^6.3.5", "vite": "^6.3.5",
"vue": "^3.5.13", "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 esbuild from "rollup-plugin-esbuild";
import { dts } from "rollup-plugin-dts"; import { dts } from "rollup-plugin-dts";
import css from "rollup-plugin-import-css"; import css from "rollup-plugin-import-css";
import { defineConfig } from "rollup";
/** /**
* Modifies the Rollup options for a build to support strict CSP * 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, false)),
...builds.map((options) => configBuild(options, true)), ...builds.map((options) => configBuild(options, true)),
{ {
input: "src/index.d.ts", input: "src/index.ts",
plugins: [dts()], plugins: [
dts({
// https://github.com/unjs/unbuild/pull/57/files
compilerOptions: {
preserveSymlinks: false,
},
}),
{
load(id) {
if (id.endsWith(".css")) return "";
},
},
],
output: [ output: [
{ {
file: "dist/index.d.ts", file: "dist/index.d.ts",
@ -90,4 +103,4 @@ export default [
}, },
], ],
}, },
]; ]);

View File

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

View File

@ -2,16 +2,18 @@ import { inject, computed, watchEffect } from "vue";
import { toValue } from "../utils"; import { toValue } from "../utils";
import type { Ref, InjectionKey, PropType } from "vue"; 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 = export const LOADING_OPTIONS_KEY: InjectionKey<LoadingOptionsInjection> =
"ecLoadingOptions" as unknown as InjectionKey< Symbol();
LoadingOptions | Ref<LoadingOptions>
>;
export function useLoading( export function useLoading(
chart: Ref<EChartsType | undefined>, chart: Ref<EChartsType | undefined>,
loading: Ref<boolean>, loading: Ref<boolean | undefined>,
loadingOptions: Ref<LoadingOptions | undefined>, loadingOptions: Ref<LoadingOptions | undefined>,
): void { ): void {
const defaultLoadingOptions = inject(LOADING_OPTIONS_KEY, {}); 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 Theme = NonNullable<InitParameters[1]>;
export type ThemeInjection = Injection<Theme>; export type ThemeInjection = Injection<Theme>;
export type InitOptions = NonNullable<InitParameters[2]>; export type InitOptions = NonNullable<InitParameters[2]>;
export type InitOptionsInjection = Injection<InitOptions>; export type InitOptionsInjection = Injection<InitOptions>;
export type UpdateOptions = SetOptionOpts; export type UpdateOptions = SetOptionOpts;
export type UpdateOptionsInjection = Injection<UpdateOptions>; export type UpdateOptionsInjection = Injection<UpdateOptions>;
export type EChartsType = ReturnType<InitType>; export type EChartsType = ReturnType<InitType>;
type SetOptionType = EChartsType["setOption"]; export type SetOptionType = EChartsType["setOption"];
export type Option = Parameters<SetOptionType>[0]; export type Option = Parameters<SetOptionType>[0];
export type AutoResize = export type AutoResize =

View File

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