apache / echarts

Apache ECharts is a powerful, interactive charting and data visualization library for browser
https://echarts.apache.org
Apache License 2.0
60.75k stars 19.62k forks source link

[Bug] tooltip.formatter option is not typed correctly #19064

Open yay opened 1 year ago

yay commented 1 year ago

Version

5.4.2

Link to Minimal Reproduction

https://github.com/yay/echarts-tooltip-type-bug

Steps to Reproduce

Uncomment the following piece of code in main.ts in the linked GitHub repo to see the TypeScript error:

// tooltip: {
//   formatter: (params) => {
//     return `${params.name}, ${params.seriesName}`; // BUG: `name` and `seriesName` are unavailable because of incorrect typing
//   },
// },

Current Behavior

Can't access name, seriesName (and other props that are actually populated) in the params object passed to the tooltip formatter function because of incorrect typing echarts exposes.

Expected Behavior

Expected to access name, seriesName and other fields on the params object that are de facto there, but are missing in the declared type.

Environment

- OS: macOS 13.5
- Browser: Chrome 115.0.5790.170 (Official Build) (arm64)
- Framework: echarts 5.4.2 in a vanilla TypeScript app

Any additional comments?

No response

ChepteaCatalin commented 1 year ago

@yay I suggest you use the following workaround, which appears less awkward:

        tooltip: {
            formatter: (params: echarts.DefaultLabelFormatterCallbackParams) => {
                return `${params.name}, ${params.seriesName}`;
            }
        } as echarts.TooltipComponentOption

params is expected to be of type TooltipComponentFormatterCallbackParams which is an alias for

type TopLevelFormatterParams = CallbackDataParams | CallbackDataParams[];

TypeScript will try to infer the most general type from the union that encompasses both possibilities even if you want to infer only CallbackDataParams type. In your case, CallbackDataParams[] is inferred because it's more general than just CallbackDataParams. So, you have to set explicitly that you want CallbackDataParams, which is exported as DefaultLabelFormatterCallbackParams.

As mentioned in the documentation, params can take the form of either an object or an array so I don't think that we should change anything in the library. @plainheart, what are your thoughts on this?

yay commented 1 year ago

@ChepteaCatalin Thanks! Yes, I've already switched to a slightly shorter type since I created this issue, which is similar to your suggestion:

formatter: ((params: echartsTypes.DefaultLabelFormatterCallbackParams[]) => {
  ...
}) as echartsTypes.TooltipComponentOption['formatter'],
ChepteaCatalin commented 1 year ago

@yay, Yes, that is also fine.

@plainheart, should we close this issue?

kewp commented 1 year ago

Hi, thanks for this, having the same issue trying to use Typescript with echarts.

I'm still getting an error when trying to access a variable called axisValue.

Property 'axisValue' does not exist on type 'CallbackDataParams'

I can see the value on the object if I log out params but it's not on the type?

Screenshot 2023-09-19 at 09 25 36
kewp commented 1 year ago

Sorry if I'm misunderstanding something but I'm also getting this type error (given the solution above):

Type '{ trigger: "axis"; axisPointer: { type: "shadow"; }; formatter: (params: CallbackDataParams[]) => string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined; }' is not assignable to type 'TooltipOption | TooltipOption[] | undefined'.
  Types of property 'formatter' are incompatible.
    Type '(params: CallbackDataParams[]) => string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined' is not assignable to type 'string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined'.
      Type '(params: CallbackDataParams[]) => string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined' is not assignable to type 'TooltipFormatterCallback<TopLevelFormatterParams>'.
        Types of parameters 'params' and 'params' are incompatible.
          Type 'TopLevelFormatterParams' is not assignable to type 'CallbackDataParams[]'.
            Type 'CallbackDataParams' is missing the following properties from type 'CallbackDataParams[]': length, pop, push, concat, and 35 more.ts(2322)

This is how I typed the function:

formatter: function(params: echarts.DefaultLabelFormatterCallbackParams[]) {
ChepteaCatalin commented 1 year ago

Sorry if I'm misunderstanding something but I'm also getting this type error (given the solution above):

Type '{ trigger: "axis"; axisPointer: { type: "shadow"; }; formatter: (params: CallbackDataParams[]) => string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined; }' is not assignable to type 'TooltipOption | TooltipOption[] | undefined'.
  Types of property 'formatter' are incompatible.
    Type '(params: CallbackDataParams[]) => string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined' is not assignable to type 'string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined'.
      Type '(params: CallbackDataParams[]) => string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined' is not assignable to type 'TooltipFormatterCallback<TopLevelFormatterParams>'.
        Types of parameters 'params' and 'params' are incompatible.
          Type 'TopLevelFormatterParams' is not assignable to type 'CallbackDataParams[]'.
            Type 'CallbackDataParams' is missing the following properties from type 'CallbackDataParams[]': length, pop, push, concat, and 35 more.ts(2322)

This is how I typed the function:

formatter: function(params: echarts.DefaultLabelFormatterCallbackParams[]) {

Try to type the function as follows:

formatter: function(params: echarts.DefaultLabelFormatterCallbackParams) {
kewp commented 1 year ago

@ChepteaCatalin the issue with that is that I'm assuming that params is an array so params[0].axisLabel gives me this error:

Element implicitly has an 'any' type because expression of type '0' can't be used to index type 'CallbackDataParams'.
  Property '0' does not exist on type 'CallbackDataParams'
kewp commented 1 year ago

In fact, I'm still getting an error on the function as well:

Type '{ trigger: "axis"; axisPointer: { type: "shadow"; }; formatter: (params: CallbackDataParams) => string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined; }' is not assignable to type 'TooltipOption | TooltipOption[] | undefined'.
  Types of property 'formatter' are incompatible.
    Type '(params: CallbackDataParams) => string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined' is not assignable to type 'string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined'.
      Type '(params: CallbackDataParams) => string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined' is not assignable to type 'TooltipFormatterCallback<TopLevelFormatterParams>'.
        Types of parameters 'params' and 'params' are incompatible.
          Type 'TopLevelFormatterParams' is not assignable to type 'CallbackDataParams'.
            Type 'CallbackDataParams[]' is missing the following properties from type 'CallbackDataParams': componentType, componentSubType, componentIndex, name, and 4 more.ts(2322)
(property) EChartsOption.tooltip?: TooltipComponentOption | TooltipComponentOption[] | undefined
ChepteaCatalin commented 1 year ago

@ChepteaCatalin the issue with that is that I'm assuming that params is an array so params[0].axisLabel gives me this error:

Element implicitly has an 'any' type because expression of type '0' can't be used to index type 'CallbackDataParams'.
  Property '0' does not exist on type 'CallbackDataParams'

That's because tooltip formatter params don't have axisLabel property.

ChepteaCatalin commented 1 year ago

In fact, I'm still getting an error on the function as well:

Type '{ trigger: "axis"; axisPointer: { type: "shadow"; }; formatter: (params: CallbackDataParams) => string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined; }' is not assignable to type 'TooltipOption | TooltipOption[] | undefined'.
  Types of property 'formatter' are incompatible.
    Type '(params: CallbackDataParams) => string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined' is not assignable to type 'string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined'.
      Type '(params: CallbackDataParams) => string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined' is not assignable to type 'TooltipFormatterCallback<TopLevelFormatterParams>'.
        Types of parameters 'params' and 'params' are incompatible.
          Type 'TopLevelFormatterParams' is not assignable to type 'CallbackDataParams'.
            Type 'CallbackDataParams[]' is missing the following properties from type 'CallbackDataParams': componentType, componentSubType, componentIndex, name, and 4 more.ts(2322)
(property) EChartsOption.tooltip?: TooltipComponentOption | TooltipComponentOption[] | undefined

Try to typecast formatter function as echartsTypes.TooltipComponentOption['formatter'] or typecast the whole tooltip option as echarts.TooltipComponentOption

kewp commented 1 year ago

That's because tooltip formatter params don't have axisLabel property.

But I saw the axisLabel on the params object when I log it to console?

It seems like name works (and is the same as axisLabel?) so if I use params[0].name and typecase the whole tooltip as you suggest it fixes the problem. Thank you

ChepteaCatalin commented 1 year ago

That's because tooltip formatter params don't have axisLabel property.

But I saw the axisLabel on the params object when I log it to console?

It seems like name works (and is the same as axisLabel?) so if I use params[0].name and typecase the whole tooltip as you suggest it fixes the problem. Thank you

Maybe you want axisValueLabel from params, because I don't see axisLabel in your screenshot and it should not exist there.

kewp commented 1 year ago

Maybe you want axisValueLabel from params, because I don't see axisLabel in your screenshot and it should not exist there.

Ah you're right. Sorry, my mistake.

ChepteaCatalin commented 1 year ago

Maybe you want axisValueLabel from params, because I don't see axisLabel in your screenshot and it should not exist there.

Ah you're right. Sorry, my mistake.

No worries

gouku commented 7 months ago

Got the same error when set params: echarts.DefaultLabelFormatterCallbackParams[]:

Type '{ trigger: "axis"; formatter: (params: echarts.DefaultLabelFormatterCallbackParams[]) => string; appendToBody: true; confine: true; backgroundColor: string; borderColor: string; textStyle: { color: string; }; extraCssText: string; }' is not assignable to type 'Arrayable<TooltipOption> | undefined'.
  Types of property 'formatter' are incompatible.
    Type '(params: echarts.DefaultLabelFormatterCallbackParams[]) => string' is not assignable to type 'string | TooltipFormatterCallback<TopLevelFormatterParams> | undefined'.
      Type '(params: echarts.DefaultLabelFormatterCallbackParams[]) => string' is not assignable to type 'TooltipFormatterCallback<TopLevelFormatterParams>'.
        Types of parameters 'params' and 'params' are incompatible.
          Type 'TopLevelFormatterParams' is not assignable to type 'CallbackDataParams[]'.
            Type 'CallbackDataParams' is missing the following properties from type 'CallbackDataParams[]': length, pop, push, concat, and 35 more.ts
YornQiu commented 3 days ago

In the charts which have axis, there are fields axisDim, axisId, axisIndex, axisType, axisValue and axisValueLabel in tooltip formatter callback params.

But they did not be defined in the type declaration. So I am destined to see typescript errors.

How to fix it?

This is what I get in console

image

This is the declaration in echarts.d.ts

image