You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by sh...@apache.org on 2022/01/04 08:46:28 UTC

[echarts] 01/01: style: using utility methods for type checking.

This is an automated email from the ASF dual-hosted git repository.

shenyi pushed a commit to branch optimize-code
in repository https://gitbox.apache.org/repos/asf/echarts.git

commit 53babd2b4c83e875f8df6c370b356d6b44c1919c
Author: pissang <bm...@gmail.com>
AuthorDate: Tue Jan 4 16:45:38 2022 +0800

    style: using utility methods for type checking.
---
 src/animation/basicTrasition.ts                |  7 +++--
 src/chart/funnel/funnelLayout.ts               |  5 ++--
 src/chart/gauge/GaugeView.ts                   |  6 ++--
 src/chart/graph/categoryFilter.ts              |  3 +-
 src/chart/graph/categoryVisual.ts              |  4 +--
 src/chart/helper/EffectLine.ts                 |  2 +-
 src/chart/helper/createClipPathFromCoordSys.ts |  3 +-
 src/chart/helper/multipleGraphEdgeHelper.ts    |  2 +-
 src/chart/helper/treeHelper.ts                 |  2 +-
 src/chart/line/LineView.ts                     |  8 ++---
 src/chart/lines/LinesSeries.ts                 |  4 +--
 src/chart/pie/labelLayout.ts                   |  4 +--
 src/chart/sankey/SankeyView.ts                 | 19 +++++++-----
 src/chart/sunburst/SunburstPiece.ts            |  2 +-
 src/chart/sunburst/sunburstLayout.ts           |  2 +-
 src/chart/sunburst/sunburstVisual.ts           | 12 ++------
 src/component/axis/AxisBuilder.ts              | 12 ++++----
 src/component/calendar/CalendarView.ts         |  6 ++--
 src/component/legend/LegendModel.ts            |  4 +--
 src/component/legend/LegendView.ts             |  6 ++--
 src/component/marker/MarkAreaView.ts           |  6 ++--
 src/component/marker/MarkLineView.ts           |  5 ++--
 src/component/toolbox/ToolboxView.ts           |  4 +--
 src/component/toolbox/feature/DataView.ts      |  6 ++--
 src/component/toolbox/feature/SaveAsImage.ts   |  4 ++-
 src/coord/axisHelper.ts                        |  4 +--
 src/coord/geo/Geo.ts                           |  2 +-
 src/coord/geo/GeoModel.ts                      |  4 +--
 src/coord/radar/Radar.ts                       |  4 +--
 src/coord/radar/RadarModel.ts                  |  4 +--
 src/core/echarts.ts                            |  9 +++---
 src/data/Graph.ts                              |  4 +--
 src/data/OrdinalMeta.ts                        |  4 +--
 src/data/SeriesData.ts                         | 10 +++----
 src/data/Tree.ts                               |  2 +-
 src/data/helper/dataValueHelper.ts             | 26 +++++++---------
 src/data/helper/transform.ts                   |  4 +--
 src/label/sectorLabel.ts                       |  4 +--
 src/model/Model.ts                             | 41 --------------------------
 src/model/mixin/dataFormat.ts                  |  4 +--
 src/processor/dataSample.ts                    |  5 ++--
 src/processor/negativeDataFilter.ts            |  3 +-
 src/scale/Ordinal.ts                           |  4 +--
 src/scale/Time.ts                              |  4 +--
 src/util/clazz.ts                              |  2 +-
 src/util/conditionalExpression.ts              |  6 ++--
 src/util/decal.ts                              | 23 +++++++--------
 src/util/model.ts                              | 14 ++++-----
 src/util/number.ts                             |  6 ++--
 src/util/time.ts                               |  6 ++--
 src/visual/VisualMapping.ts                    |  2 +-
 src/visual/aria.ts                             |  4 +--
 src/visual/style.ts                            |  4 +--
 53 files changed, 153 insertions(+), 194 deletions(-)

diff --git a/src/animation/basicTrasition.ts b/src/animation/basicTrasition.ts
index 3863b6b..a9de354 100644
--- a/src/animation/basicTrasition.ts
+++ b/src/animation/basicTrasition.ts
@@ -29,6 +29,7 @@ import { AnimationEasing } from 'zrender/src/animation/easing';
 import Element, { ElementAnimateConfig } from 'zrender/src/Element';
 import Model from '../model/Model';
 import {
+    isFunction,
     isObject,
     retrieve2
 } from 'zrender/src/core/util';
@@ -101,13 +102,13 @@ export function getAnimationConfig(
             animationPayload.easing != null && (easing = animationPayload.easing);
             animationPayload.delay != null && (delay = animationPayload.delay);
         }
-        if (typeof delay === 'function') {
+        if (isFunction(delay)) {
             delay = delay(
                 dataIndex as number,
                 extraDelayParams
             );
         }
-        if (typeof duration === 'function') {
+        if (isFunction(duration)) {
             duration = duration(dataIndex as number);
         }
         const config = {
@@ -136,7 +137,7 @@ function animateOrSetProps<Props>(
 ) {
     let isFrom = false;
     let removeOpt: AnimationOption;
-    if (typeof dataIndex === 'function') {
+    if (isFunction(dataIndex)) {
         during = cb;
         cb = dataIndex;
         dataIndex = null;
diff --git a/src/chart/funnel/funnelLayout.ts b/src/chart/funnel/funnelLayout.ts
index cb11676..4d433c1 100644
--- a/src/chart/funnel/funnelLayout.ts
+++ b/src/chart/funnel/funnelLayout.ts
@@ -23,6 +23,7 @@ import FunnelSeriesModel, { FunnelSeriesOption, FunnelDataItemOption } from './F
 import ExtensionAPI from '../../core/ExtensionAPI';
 import SeriesData from '../../data/SeriesData';
 import GlobalModel from '../../model/Global';
+import { isFunction } from 'zrender/src/core/util';
 
 function getViewRect(seriesModel: FunnelSeriesModel, api: ExtensionAPI) {
     return layout.getLayoutRect(
@@ -45,8 +46,8 @@ function getSortedIndices(data: SeriesData, sort: FunnelSeriesOption['sort']) {
     }
 
     // Add custom sortable function & none sortable opetion by "options.sort"
-    if (typeof sort === 'function') {
-        indices.sort(sort);
+    if (isFunction(sort)) {
+        indices.sort(sort as any);
     }
     else if (sort !== 'none') {
         indices.sort(function (a, b) {
diff --git a/src/chart/gauge/GaugeView.ts b/src/chart/gauge/GaugeView.ts
index 4617318..85b7416 100644
--- a/src/chart/gauge/GaugeView.ts
+++ b/src/chart/gauge/GaugeView.ts
@@ -31,7 +31,7 @@ import SeriesData from '../../data/SeriesData';
 import Sausage from '../../util/shape/sausage';
 import {createSymbol} from '../../util/symbol';
 import ZRImage from 'zrender/src/graphic/Image';
-import {extend} from 'zrender/src/core/util';
+import {extend, isFunction, isString} from 'zrender/src/core/util';
 import {setCommonECData} from '../../util/innerStore';
 
 type ECSymbol = ReturnType<typeof createSymbol>;
@@ -61,10 +61,10 @@ function parsePosition(seriesModel: GaugeSeriesModel, api: ExtensionAPI): PosInf
 function formatLabel(value: number, labelFormatter: string | ((value: number) => string)): string {
     let label = value == null ? '' : (value + '');
     if (labelFormatter) {
-        if (typeof labelFormatter === 'string') {
+        if (isString(labelFormatter)) {
             label = labelFormatter.replace('{value}', label);
         }
-        else if (typeof labelFormatter === 'function') {
+        else if (isFunction(labelFormatter)) {
             label = labelFormatter(value);
         }
     }
diff --git a/src/chart/graph/categoryFilter.ts b/src/chart/graph/categoryFilter.ts
index b0aa3b1..1bd630f 100644
--- a/src/chart/graph/categoryFilter.ts
+++ b/src/chart/graph/categoryFilter.ts
@@ -20,6 +20,7 @@
 import GlobalModel from '../../model/Global';
 import GraphSeriesModel, { GraphNodeItemOption } from './GraphSeries';
 import type LegendModel from '../../component/legend/LegendModel';
+import { isNumber } from 'zrender/src/core/util';
 
 export default function categoryFilter(ecModel: GlobalModel) {
     const legendModels = ecModel.findComponents({
@@ -39,7 +40,7 @@ export default function categoryFilter(ecModel: GlobalModel) {
             const model = data.getItemModel<GraphNodeItemOption>(idx);
             let category = model.getShallow('category');
             if (category != null) {
-                if (typeof category === 'number') {
+                if (isNumber(category)) {
                     category = categoryNames[category];
                 }
                 // If in any legend component the status is not selected.
diff --git a/src/chart/graph/categoryVisual.ts b/src/chart/graph/categoryVisual.ts
index fb6c9ed..acc8959 100644
--- a/src/chart/graph/categoryVisual.ts
+++ b/src/chart/graph/categoryVisual.ts
@@ -20,7 +20,7 @@
 import GlobalModel from '../../model/Global';
 import GraphSeriesModel, { GraphNodeItemOption } from './GraphSeries';
 import { Dictionary, ColorString } from '../../util/types';
-import { extend } from 'zrender/src/core/util';
+import { extend, isString } from 'zrender/src/core/util';
 
 export default function categoryVisual(ecModel: GlobalModel) {
 
@@ -60,7 +60,7 @@ export default function categoryVisual(ecModel: GlobalModel) {
                 const model = data.getItemModel<GraphNodeItemOption>(idx);
                 let categoryIdx = model.getShallow('category');
                 if (categoryIdx != null) {
-                    if (typeof categoryIdx === 'string') {
+                    if (isString(categoryIdx)) {
                         categoryIdx = categoryNameIdxMap['ec-' + categoryIdx];
                     }
 
diff --git a/src/chart/helper/EffectLine.ts b/src/chart/helper/EffectLine.ts
index bc92620..3843e68 100644
--- a/src/chart/helper/EffectLine.ts
+++ b/src/chart/helper/EffectLine.ts
@@ -143,7 +143,7 @@ class EffectLine extends graphic.Group {
 
             if (period > 0) {
                 let delayNum: number;
-                if (typeof delayExpr === 'function') {
+                if (zrUtil.isFunction(delayExpr)) {
                     delayNum = delayExpr(idx);
                 }
                 else {
diff --git a/src/chart/helper/createClipPathFromCoordSys.ts b/src/chart/helper/createClipPathFromCoordSys.ts
index 85695cc..7bc83d7 100644
--- a/src/chart/helper/createClipPathFromCoordSys.ts
+++ b/src/chart/helper/createClipPathFromCoordSys.ts
@@ -24,6 +24,7 @@ import { SeriesOption } from '../../util/types';
 import type Cartesian2D from '../../coord/cartesian/Cartesian2D';
 import type Polar from '../../coord/polar/Polar';
 import { CoordinateSystem } from '../../coord/CoordinateSystem';
+import { isFunction } from 'zrender/src/core/util';
 
 type SeriesModelWithLineWidth = SeriesModel<SeriesOption & {
     lineStyle?: { width?: number }
@@ -80,7 +81,7 @@ function createGridClipPath(
             clipPath.shape.height = 0;
         }
 
-        const duringCb = typeof during === 'function'
+        const duringCb = isFunction(during)
             ? (percent: number) => {
                 during(percent, clipPath);
             }
diff --git a/src/chart/helper/multipleGraphEdgeHelper.ts b/src/chart/helper/multipleGraphEdgeHelper.ts
index bd49e44..8449363 100644
--- a/src/chart/helper/multipleGraphEdgeHelper.ts
+++ b/src/chart/helper/multipleGraphEdgeHelper.ts
@@ -42,7 +42,7 @@ const createCurveness = function (seriesModel, appendLength) {
     let curvenessList = [];
 
     // handler the function set
-    if (typeof autoCurvenessParmas === 'number') {
+    if (zrUtil.isNumber(autoCurvenessParmas)) {
         length = autoCurvenessParmas;
     }
     else if (zrUtil.isArray(autoCurvenessParmas)) {
diff --git a/src/chart/helper/treeHelper.ts b/src/chart/helper/treeHelper.ts
index 1a4a701..c96b728 100644
--- a/src/chart/helper/treeHelper.ts
+++ b/src/chart/helper/treeHelper.ts
@@ -34,7 +34,7 @@ export function retrieveTargetInfo(
         const root = seriesModel.getData().tree.root;
         let targetNode = payload.targetNode;
 
-        if (typeof targetNode === 'string') {
+        if (zrUtil.isString(targetNode)) {
             targetNode = root.getNodeById(targetNode);
         }
 
diff --git a/src/chart/line/LineView.ts b/src/chart/line/LineView.ts
index 97059f6..64e388b 100644
--- a/src/chart/line/LineView.ts
+++ b/src/chart/line/LineView.ts
@@ -124,7 +124,7 @@ function getBoundingDiff(points1: ArrayLike<number>, points2: ArrayLike<number>)
 }
 
 function getSmooth(smooth: number | boolean) {
-    return typeof smooth === 'number' ? smooth : (smooth ? 0.5 : 0);
+    return zrUtil.isNumber(smooth) ? smooth : (smooth ? 0.5 : 0);
 }
 
 function getStackedOnPoints(
@@ -1064,11 +1064,11 @@ class LineView extends ChartView {
 
         const seriesModel = data.hostModel;
         let seriesDuration = seriesModel.get('animationDuration');
-        if (typeof seriesDuration === 'function') {
+        if (zrUtil.isFunction(seriesDuration)) {
             seriesDuration = seriesDuration(null);
         }
         const seriesDalay = seriesModel.get('animationDelay') || 0;
-        const seriesDalayValue = typeof seriesDalay === 'function'
+        const seriesDalayValue = zrUtil.isFunction(seriesDalay)
             ? seriesDalay(null)
             : seriesDalay;
 
@@ -1113,7 +1113,7 @@ class LineView extends ChartView {
                     ratio = 1 - ratio;
                 }
 
-                const delay = typeof seriesDalay === 'function' ? seriesDalay(idx)
+                const delay = zrUtil.isFunction(seriesDalay) ? seriesDalay(idx)
                     : (seriesDuration * ratio) + seriesDalayValue;
 
                 const symbolPath = el.getSymbolPath();
diff --git a/src/chart/lines/LinesSeries.ts b/src/chart/lines/LinesSeries.ts
index 09304c6..03a08df 100644
--- a/src/chart/lines/LinesSeries.ts
+++ b/src/chart/lines/LinesSeries.ts
@@ -21,7 +21,7 @@
 
 import SeriesModel from '../../model/Series';
 import SeriesData from '../../data/SeriesData';
-import { concatArray, mergeAll, map } from 'zrender/src/core/util';
+import { concatArray, mergeAll, map, isNumber } from 'zrender/src/core/util';
 import CoordinateSystem from '../../core/CoordinateSystem';
 import {
     SeriesOption,
@@ -259,7 +259,7 @@ class LinesSeriesModel extends SeriesModel<LinesSeriesOption> {
         }
         // Stored as a typed array. In format
         // Points Count(2) | x | y | x | y | Points Count(3) | x |  y | x | y | x | y |
-        if (typeof data[0] === 'number') {
+        if (isNumber(data[0])) {
             const len = data.length;
             // Store offset and len of each segment
             const coordsOffsetAndLenStorage = new Uint32Arr(len) as Uint32Array;
diff --git a/src/chart/pie/labelLayout.ts b/src/chart/pie/labelLayout.ts
index 14be831..c8fa9a4 100644
--- a/src/chart/pie/labelLayout.ts
+++ b/src/chart/pie/labelLayout.ts
@@ -25,7 +25,7 @@ import { HorizontalAlign, ZRTextAlign } from '../../util/types';
 import { Sector, Polyline, Point } from '../../util/graphic';
 import ZRText from 'zrender/src/graphic/Text';
 import BoundingRect, {RectLike} from 'zrender/src/core/BoundingRect';
-import { each } from 'zrender/src/core/util';
+import { each, isNumber } from 'zrender/src/core/util';
 import { limitTurnAngle, limitSurfaceAngle } from '../../label/labelGuideHelper';
 import { shiftLayoutOnY } from '../../label/labelLayoutHelper';
 
@@ -352,7 +352,7 @@ export default function pieLabelLayout(
 
         let labelRotate;
         const rotate = labelModel.get('rotate');
-        if (typeof rotate === 'number') {
+        if (isNumber(rotate)) {
             labelRotate = rotate * (Math.PI / 180);
         }
         else if (labelPosition === 'center') {
diff --git a/src/chart/sankey/SankeyView.ts b/src/chart/sankey/SankeyView.ts
index 863f1c3..f7e3852 100644
--- a/src/chart/sankey/SankeyView.ts
+++ b/src/chart/sankey/SankeyView.ts
@@ -29,6 +29,7 @@ import SeriesData from '../../data/SeriesData';
 import { RectLike } from 'zrender/src/core/BoundingRect';
 import { setLabelStyle, getLabelStatesModels } from '../../label/labelStyle';
 import { getECData } from '../../util/innerStore';
+import { isString } from 'zrender/src/core/util';
 
 class SankeyPathShape {
     x1 = 0;
@@ -206,14 +207,16 @@ class SankeyView extends ChartView {
                 case 'gradient':
                     const sourceColor = edge.node1.getVisual('color');
                     const targetColor = edge.node2.getVisual('color');
-                    if (typeof sourceColor === 'string' && typeof targetColor === 'string') {
-                        curve.style.fill = new graphic.LinearGradient(0, 0, +(orient === 'horizontal'), +(orient === 'vertical'), [{
-                            color: sourceColor,
-                            offset: 0
-                        }, {
-                            color: targetColor,
-                            offset: 1
-                        }]);
+                    if (isString(sourceColor) && isString(targetColor)) {
+                        curve.style.fill = new graphic.LinearGradient(
+                            0, 0, +(orient === 'horizontal'), +(orient === 'vertical'), [{
+                                color: sourceColor,
+                                offset: 0
+                            }, {
+                                color: targetColor,
+                                offset: 1
+                            }]
+                        );
                     }
             }
 
diff --git a/src/chart/sunburst/SunburstPiece.ts b/src/chart/sunburst/SunburstPiece.ts
index b5cfd99..e507a05 100644
--- a/src/chart/sunburst/SunburstPiece.ts
+++ b/src/chart/sunburst/SunburstPiece.ts
@@ -259,7 +259,7 @@ class SunburstPiece extends graphic.Sector {
                     rotate += Math.PI;
                 }
             }
-            else if (typeof rotateType === 'number') {
+            else if (zrUtil.isNumber(rotateType)) {
                 rotate = rotateType * Math.PI / 180;
             }
 
diff --git a/src/chart/sunburst/sunburstLayout.ts b/src/chart/sunburst/sunburstLayout.ts
index 5578ead..2ec6269 100644
--- a/src/chart/sunburst/sunburstLayout.ts
+++ b/src/chart/sunburst/sunburstLayout.ts
@@ -205,7 +205,7 @@ function initChildren(node: TreeNode, sortOrder?: SunburstSeriesOption['sort'])
  *                                   See SunburstSeries.js for details.
  */
 function sort(children: TreeNode[], sortOrder: SunburstSeriesOption['sort']) {
-    if (typeof sortOrder === 'function') {
+    if (zrUtil.isFunction(sortOrder)) {
         const sortTargets = zrUtil.map(children, (child, idx) => {
             const value = child.getValue() as number;
             return {
diff --git a/src/chart/sunburst/sunburstVisual.ts b/src/chart/sunburst/sunburstVisual.ts
index f43a961..134fc14 100644
--- a/src/chart/sunburst/sunburstVisual.ts
+++ b/src/chart/sunburst/sunburstVisual.ts
@@ -18,18 +18,12 @@
 */
 
 import { lift } from 'zrender/src/tool/color';
-import { extend, map } from 'zrender/src/core/util';
+import { extend, isString } from 'zrender/src/core/util';
 import GlobalModel from '../../model/Global';
 import SunburstSeriesModel, { SunburstSeriesNodeItemOption } from './SunburstSeries';
-import { Dictionary, ColorString, ZRColor } from '../../util/types';
-import { setItemVisualFromData } from '../../visual/helper';
+import { Dictionary, ColorString } from '../../util/types';
 import { TreeNode } from '../../data/Tree';
 
-type ParentColorMap = {
-    node: TreeNode,
-    parentColor: ZRColor
-};
-
 export default function sunburstVisual(ecModel: GlobalModel) {
 
     const paletteScope: Dictionary<ColorString> = {};
@@ -42,7 +36,7 @@ export default function sunburstVisual(ecModel: GlobalModel) {
             current = current.parentNode;
         }
         let color = seriesModel.getColorFromPalette((current.name || current.dataIndex + ''), paletteScope);
-        if (node.depth > 1 && typeof color === 'string') {
+        if (node.depth > 1 && isString(color)) {
             // Lighter on the deeper level.
             color = lift(color, (node.depth - 1) / (treeHeight - 1) * 0.5);
         }
diff --git a/src/component/axis/AxisBuilder.ts b/src/component/axis/AxisBuilder.ts
index d06c0b5..f065369 100644
--- a/src/component/axis/AxisBuilder.ts
+++ b/src/component/axis/AxisBuilder.ts
@@ -17,7 +17,7 @@
 * under the License.
 */
 
-import {retrieve, defaults, extend, each, isObject, map} from 'zrender/src/core/util';
+import {retrieve, defaults, extend, each, isObject, map, isString, isNumber, isFunction} from 'zrender/src/core/util';
 import * as graphic from '../../util/graphic';
 import {getECData} from '../../util/innerStore';
 import {createTextStyle} from '../../label/labelStyle';
@@ -287,15 +287,13 @@ const builders: Record<'axisLine' | 'axisTickLabel' | 'axisName', AxisElementsBu
         if (arrows != null) {
             let arrowSize = axisModel.get(['axisLine', 'symbolSize']);
 
-            if (typeof arrows === 'string') {
+            if (isString(arrows)) {
                 // Use the same arrow for start and end point
                 arrows = [arrows, arrows];
             }
-            if (typeof arrowSize === 'string'
-                || typeof arrowSize === 'number'
-            ) {
+            if (isString(arrowSize) || isNumber(arrowSize)) {
                 // Use the same size for width and height
-                arrowSize = [arrowSize, arrowSize];
+                arrowSize = [arrowSize as number, arrowSize as number];
             }
 
             const arrowOffset = normalizeSymbolOffset(axisModel.get(['axisLine', 'symbolOffset']) || 0, arrowSize);
@@ -789,7 +787,7 @@ function buildAxisLabel(
                 verticalAlign: itemLabelModel.getShallow('verticalAlign', true)
                     || itemLabelModel.getShallow('baseline', true)
                     || labelLayout.textVerticalAlign,
-                fill: typeof textColor === 'function'
+                fill: isFunction(textColor)
                     ? textColor(
                         // (1) In category axis with data zoom, tick is not the original
                         // index of axis.data. So tick should not be exposed to user
diff --git a/src/component/calendar/CalendarView.ts b/src/component/calendar/CalendarView.ts
index 1eecd0b..6cc7274 100644
--- a/src/component/calendar/CalendarView.ts
+++ b/src/component/calendar/CalendarView.ts
@@ -17,7 +17,7 @@
 * under the License.
 */
 
-import { isString, extend, map } from 'zrender/src/core/util';
+import { isString, extend, map, isFunction } from 'zrender/src/core/util';
 import * as graphic from '../../util/graphic';
 import {createTextStyle} from '../../label/labelStyle';
 import { formatTplSimple } from '../../util/format';
@@ -229,11 +229,11 @@ class CalendarView extends ComponentView {
         params: T
     ) {
 
-        if (typeof formatter === 'string' && formatter) {
+        if (isString(formatter) && formatter) {
             return formatTplSimple(formatter, params);
         }
 
-        if (typeof formatter === 'function') {
+        if (isFunction(formatter)) {
             return formatter(params);
         }
 
diff --git a/src/component/legend/LegendModel.ts b/src/component/legend/LegendModel.ts
index a9f35a2..b121c94 100644
--- a/src/component/legend/LegendModel.ts
+++ b/src/component/legend/LegendModel.ts
@@ -356,9 +356,9 @@ class LegendModel<Ops extends LegendOption = LegendOption> extends ComponentMode
 
         const legendData = zrUtil.map(rawData, function (dataItem) {
             // Can be string or number
-            if (typeof dataItem === 'string' || typeof dataItem === 'number') {
+            if (zrUtil.isString(dataItem) || zrUtil.isNumber(dataItem)) {
                 dataItem = {
-                    name: dataItem
+                    name: dataItem as string
                 };
             }
             return new Model(dataItem, this, this.ecModel);
diff --git a/src/component/legend/LegendView.ts b/src/component/legend/LegendView.ts
index f7ce4f5..67e0145 100644
--- a/src/component/legend/LegendView.ts
+++ b/src/component/legend/LegendView.ts
@@ -366,7 +366,7 @@ class LegendView extends ComponentView {
 
         const textStyleModel = legendItemModel.getModel('textStyle');
 
-        if (typeof seriesModel.getLegendIcon === 'function'
+        if (zrUtil.isFunction(seriesModel.getLegendIcon)
             && (!legendIconType || legendIconType === 'inherit')
         ) {
             // Series has specific way to define legend icon
@@ -404,10 +404,10 @@ class LegendView extends ComponentView {
 
         const formatter = legendModel.get('formatter');
         let content = name;
-        if (typeof formatter === 'string' && formatter) {
+        if (zrUtil.isString(formatter) && formatter) {
             content = formatter.replace('{name}', name != null ? name : '');
         }
-        else if (typeof formatter === 'function') {
+        else if (zrUtil.isFunction(formatter)) {
             content = formatter(name);
         }
 
diff --git a/src/component/marker/MarkAreaView.ts b/src/component/marker/MarkAreaView.ts
index f9b762c..f98c59c 100644
--- a/src/component/marker/MarkAreaView.ts
+++ b/src/component/marker/MarkAreaView.ts
@@ -26,7 +26,7 @@ import * as graphic from '../../util/graphic';
 import { enableHoverEmphasis, setStatesStylesFromModel } from '../../util/states';
 import * as markerHelper from './markerHelper';
 import MarkerView from './MarkerView';
-import { retrieve, mergeAll, map, curry, filter, HashMap, extend } from 'zrender/src/core/util';
+import { retrieve, mergeAll, map, curry, filter, HashMap, extend, isString } from 'zrender/src/core/util';
 import { ParsedValue, ScaleDataValue, ZRColor } from '../../util/types';
 import { CoordinateSystem, isCoordinateSystemType } from '../../coord/CoordinateSystem';
 import MarkAreaModel, { MarkArea2DDataItemOption } from './MarkAreaModel';
@@ -272,7 +272,7 @@ class MarkAreaView extends MarkerView {
             const color = getVisualFromData(seriesData, 'color') as ZRColor;
             if (!style.fill) {
                 style.fill = color;
-                if (typeof style.fill === 'string') {
+                if (isString(style.fill)) {
                     style.fill = colorUtil.modifyAlpha(style.fill, 0.4);
                 }
             }
@@ -339,7 +339,7 @@ class MarkAreaView extends MarkerView {
                     labelFetcher: maModel,
                     labelDataIndex: idx,
                     defaultText: areaData.getName(idx) || '',
-                    inheritColor: typeof style.fill === 'string'
+                    inheritColor: isString(style.fill)
                         ? colorUtil.modifyAlpha(style.fill, 1) : '#000'
                 }
             );
diff --git a/src/component/marker/MarkLineView.ts b/src/component/marker/MarkLineView.ts
index 760e92f..f907f14 100644
--- a/src/component/marker/MarkLineView.ts
+++ b/src/component/marker/MarkLineView.ts
@@ -43,7 +43,8 @@ import {
     map,
     curry,
     filter,
-    HashMap
+    HashMap,
+    isNumber
 } from 'zrender/src/core/util';
 import { makeInner } from '../../util/model';
 import { LineDataVisual } from '../../visual/commonVisualTypes';
@@ -112,7 +113,7 @@ const markLineTransform = function (
             mlTo.coord[baseIndex] = Infinity;
 
             const precision = mlModel.get('precision');
-            if (precision >= 0 && typeof value === 'number') {
+            if (precision >= 0 && isNumber(value)) {
                 value = +value.toFixed(Math.min(precision, 20));
             }
 
diff --git a/src/component/toolbox/ToolboxView.ts b/src/component/toolbox/ToolboxView.ts
index 83fc699..67ea921 100644
--- a/src/component/toolbox/ToolboxView.ts
+++ b/src/component/toolbox/ToolboxView.ts
@@ -185,14 +185,14 @@ class ToolboxView extends ComponentView {
             const titles = featureModel.get('title') || {};
             let iconsMap: Dictionary<string>;
             let titlesMap: Dictionary<string>;
-            if (typeof icons === 'string') {
+            if (zrUtil.isString(icons)) {
                 iconsMap = {};
                 iconsMap[featureName] = icons;
             }
             else {
                 iconsMap = icons;
             }
-            if (typeof titles === 'string') {
+            if (zrUtil.isString(titles)) {
                 titlesMap = {};
                 titlesMap[featureName] = titles as string;
             }
diff --git a/src/component/toolbox/feature/DataView.ts b/src/component/toolbox/feature/DataView.ts
index 6256705..fe70ca1 100644
--- a/src/component/toolbox/feature/DataView.ts
+++ b/src/component/toolbox/feature/DataView.ts
@@ -341,9 +341,9 @@ class DataView extends ToolboxFeature<ToolboxDataViewFeatureOption> {
         const optionToContent = model.get('optionToContent');
         const contentToOption = model.get('contentToOption');
         const result = getContentFromModel(ecModel);
-        if (typeof optionToContent === 'function') {
+        if (zrUtil.isFunction(optionToContent)) {
             const htmlOrDom = optionToContent(api.getOption());
-            if (typeof htmlOrDom === 'string') {
+            if (zrUtil.isString(htmlOrDom)) {
                 viewMain.innerHTML = htmlOrDom;
             }
             else if (zrUtil.isDom(htmlOrDom)) {
@@ -395,7 +395,7 @@ class DataView extends ToolboxFeature<ToolboxDataViewFeatureOption> {
 
             let newOption;
             try {
-                if (typeof contentToOption === 'function') {
+                if (zrUtil.isFunction(contentToOption)) {
                     newOption = contentToOption(viewMain, api.getOption());
                 }
                 else {
diff --git a/src/component/toolbox/feature/SaveAsImage.ts b/src/component/toolbox/feature/SaveAsImage.ts
index d6bc36c..7e9c690 100644
--- a/src/component/toolbox/feature/SaveAsImage.ts
+++ b/src/component/toolbox/feature/SaveAsImage.ts
@@ -24,6 +24,7 @@ import { ToolboxFeature, ToolboxFeatureOption } from '../featureManager';
 import { ZRColor } from '../../../util/types';
 import GlobalModel from '../../../model/Global';
 import ExtensionAPI from '../../../core/ExtensionAPI';
+import { isFunction } from 'zrender/src/core/util';
 
 export interface ToolboxSaveAsImageFeatureOption extends ToolboxFeatureOption {
     icon?: string
@@ -58,8 +59,9 @@ class SaveAsImage extends ToolboxFeature<ToolboxSaveAsImageFeatureOption> {
             excludeComponents: model.get('excludeComponents'),
             pixelRatio: model.get('pixelRatio')
         });
+        const browser = env.browser;
         // Chrome, Firefox, New Edge
-        if (typeof MouseEvent === 'function' && (env.browser.newEdge || (!env.browser.ie && !env.browser.edge))) {
+        if (isFunction(MouseEvent) && (browser.newEdge || (!browser.ie && !browser.edge))) {
             const $a = document.createElement('a');
             $a.download = title + '.' + type;
             $a.target = '_blank';
diff --git a/src/coord/axisHelper.ts b/src/coord/axisHelper.ts
index e8bf8a6..c487d52 100644
--- a/src/coord/axisHelper.ts
+++ b/src/coord/axisHelper.ts
@@ -242,7 +242,7 @@ export function makeLabelFormatter(axis: Axis): (tick: ScaleTick, idx?: number)
             };
         })(labelFormatter as TimeAxisLabelFormatterOption);
     }
-    else if (typeof labelFormatter === 'string') {
+    else if (zrUtil.isString(labelFormatter)) {
         return (function (tpl) {
             return function (tick: ScaleTick) {
                 // For category axis, get raw value; for numeric axis,
@@ -254,7 +254,7 @@ export function makeLabelFormatter(axis: Axis): (tick: ScaleTick, idx?: number)
             };
         })(labelFormatter);
     }
-    else if (typeof labelFormatter === 'function') {
+    else if (zrUtil.isFunction(labelFormatter)) {
         return (function (cb) {
             return function (tick: ScaleTick, idx: number) {
                 // The original intention of `idx` is "the index of the tick in all ticks".
diff --git a/src/coord/geo/Geo.ts b/src/coord/geo/Geo.ts
index a3896c1..d150b7f 100644
--- a/src/coord/geo/Geo.ts
+++ b/src/coord/geo/Geo.ts
@@ -172,7 +172,7 @@ class Geo extends View {
     }
 
     dataToPoint(data: number[] | string, noRoam?: boolean, out?: number[]): number[] {
-        if (typeof data === 'string') {
+        if (zrUtil.isString(data)) {
             // Map area name to geoCoord
             data = this.getGeoCoord(data);
         }
diff --git a/src/coord/geo/GeoModel.ts b/src/coord/geo/GeoModel.ts
index 432c293..87c613d 100644
--- a/src/coord/geo/GeoModel.ts
+++ b/src/coord/geo/GeoModel.ts
@@ -270,11 +270,11 @@ class GeoModel extends ComponentModel<GeoOption> {
         const params = {
             name: name
         } as GeoLabelFormatterDataParams;
-        if (typeof formatter === 'function') {
+        if (zrUtil.isFunction(formatter)) {
             params.status = status;
             return formatter(params);
         }
-        else if (typeof formatter === 'string') {
+        else if (zrUtil.isString(formatter)) {
             return formatter.replace('{a}', name != null ? name : '');
         }
     }
diff --git a/src/coord/radar/Radar.ts b/src/coord/radar/Radar.ts
index 68fb878..3b5ffa4 100644
--- a/src/coord/radar/Radar.ts
+++ b/src/coord/radar/Radar.ts
@@ -28,7 +28,7 @@ import GlobalModel from '../../model/Global';
 import ExtensionAPI from '../../core/ExtensionAPI';
 import { ScaleDataValue } from '../../util/types';
 import { ParsedModelFinder } from '../../util/model';
-import { map, each } from 'zrender/src/core/util';
+import { map, each, isString, isNumber } from 'zrender/src/core/util';
 import { alignScaleTicks } from '../../scale/helper';
 
 
@@ -133,7 +133,7 @@ class Radar implements CoordinateSystem, CoordinateSystemMaster {
 
         // radius may be single value like `20`, `'80%'`, or array like `[10, '80%']`
         let radius = radarModel.get('radius');
-        if (typeof radius === 'string' || typeof radius === 'number') {
+        if (isString(radius) || isNumber(radius)) {
             radius = [0, radius];
         }
         this.r0 = numberUtil.parsePercent(radius[0], viewSize);
diff --git a/src/coord/radar/RadarModel.ts b/src/coord/radar/RadarModel.ts
index 3309e0e..2f45804 100644
--- a/src/coord/radar/RadarModel.ts
+++ b/src/coord/radar/RadarModel.ts
@@ -146,11 +146,11 @@ class RadarModel extends ComponentModel<RadarOption> implements CoordinateSystem
             if (!showName) {
                 innerIndicatorOpt.name = '';
             }
-            if (typeof nameFormatter === 'string') {
+            if (zrUtil.isString(nameFormatter)) {
                 const indName = innerIndicatorOpt.name;
                 innerIndicatorOpt.name = nameFormatter.replace('{value}', indName != null ? indName : '');
             }
-            else if (typeof nameFormatter === 'function') {
+            else if (zrUtil.isFunction(nameFormatter)) {
                 innerIndicatorOpt.name = nameFormatter(
                     innerIndicatorOpt.name, innerIndicatorOpt
                 );
diff --git a/src/core/echarts.ts b/src/core/echarts.ts
index 0b27eae..42864da 100644
--- a/src/core/echarts.ts
+++ b/src/core/echarts.ts
@@ -33,7 +33,8 @@ import {
     defaults,
     isDom,
     isArray,
-    noop
+    noop,
+    isString
 } from 'zrender/src/core/util';
 import env from 'zrender/src/core/env';
 import timsort from 'zrender/src/core/timsort';
@@ -400,7 +401,7 @@ class ECharts extends Eventful<ECEventDefinition> {
         opts = opts || {};
 
         // Get theme by name
-        if (typeof theme === 'string') {
+        if (isString(theme)) {
             theme = themeStorage[theme] as object;
         }
 
@@ -2698,7 +2699,7 @@ export const disconnect = disConnect;
  * Dispose a chart instance
  */
 export function dispose(chart: EChartsType | HTMLElement | string): void {
-    if (typeof chart === 'string') {
+    if (isString(chart)) {
         chart = instances[chart];
     }
     else if (!(chart instanceof ECharts)) {
@@ -2788,7 +2789,7 @@ export function registerAction(
     eventName: string | ActionHandler,
     action?: ActionHandler
 ): void {
-    if (typeof eventName === 'function') {
+    if (isFunction(eventName)) {
         action = eventName;
         eventName = '';
     }
diff --git a/src/data/Graph.ts b/src/data/Graph.ts
index 6ebb2ca..a250ad9 100644
--- a/src/data/Graph.ts
+++ b/src/data/Graph.ts
@@ -110,10 +110,10 @@ class Graph {
         const edgesMap = this._edgesMap;
 
         // PNEDING
-        if (typeof n1 === 'number') {
+        if (zrUtil.isNumber(n1)) {
             n1 = this.nodes[n1];
         }
-        if (typeof n2 === 'number') {
+        if (zrUtil.isNumber(n2)) {
             n2 = this.nodes[n2];
         }
 
diff --git a/src/data/OrdinalMeta.ts b/src/data/OrdinalMeta.ts
index d562736..441e012 100644
--- a/src/data/OrdinalMeta.ts
+++ b/src/data/OrdinalMeta.ts
@@ -17,7 +17,7 @@
 * under the License.
 */
 
-import {createHashMap, isObject, map, HashMap} from 'zrender/src/core/util';
+import {createHashMap, isObject, map, HashMap, isString} from 'zrender/src/core/util';
 import Model from '../model/Model';
 import { OrdinalNumber, OrdinalRawValue } from '../util/types';
 
@@ -77,7 +77,7 @@ class OrdinalMeta {
         // consider a common case: a value is 2017, which is a number but is
         // expected to be tread as a category. This case usually happen in dataset,
         // where it happent to be no need of the index feature.
-        if (typeof category !== 'string' && !needCollect) {
+        if (!isString(category) && !needCollect) {
             return category;
         }
 
diff --git a/src/data/SeriesData.ts b/src/data/SeriesData.ts
index 99b3c04..c6fd89f 100644
--- a/src/data/SeriesData.ts
+++ b/src/data/SeriesData.ts
@@ -430,7 +430,7 @@ class SeriesData<
      * @return recogonized `DimensionIndex`. Otherwise return null/undefined (means that dim is `DimensionName`).
      */
     private _recognizeDimIndex(dim: DimensionLoose): DimensionIndex {
-        if (typeof dim === 'number'
+        if (zrUtil.isNumber(dim)
             // If being a number-like string but not being defined as a dimension name.
             || (
                 dim != null
@@ -907,7 +907,7 @@ class SeriesData<
     ): void {
         'use strict';
 
-        if (typeof dims === 'function') {
+        if (zrUtil.isFunction(dims)) {
             ctx = cb as Ctx;
             cb = dims;
             dims = [];
@@ -938,7 +938,7 @@ class SeriesData<
     ): SeriesData {
         'use strict';
 
-        if (typeof dims === 'function') {
+        if (zrUtil.isFunction(dims)) {
             ctx = cb as Ctx;
             cb = dims;
             dims = [];
@@ -994,7 +994,7 @@ class SeriesData<
     ): unknown[] {
         'use strict';
 
-        if (typeof dims === 'function') {
+        if (zrUtil.isFunction(dims)) {
             ctx = cb as Ctx;
             cb = dims;
             dims = [];
@@ -1368,7 +1368,7 @@ class SeriesData<
         injectFunction: (...args: any) => any
     ): void {
         const originalMethod = this[methodName];
-        if (typeof originalMethod !== 'function') {
+        if (!zrUtil.isFunction(originalMethod)) {
             return;
         }
         this.__wrappedMethods = this.__wrappedMethods || [];
diff --git a/src/data/Tree.ts b/src/data/Tree.ts
index 3b5d4a7..ad7ae42 100644
--- a/src/data/Tree.ts
+++ b/src/data/Tree.ts
@@ -106,7 +106,7 @@ export class TreeNode {
         cb?: TreeTraverseCallback<Ctx> | Ctx,
         context?: Ctx
     ) {
-        if (typeof options === 'function') {
+        if (zrUtil.isFunction(options)) {
             context = cb as Ctx;
             cb = options;
             options = null;
diff --git a/src/data/helper/dataValueHelper.ts b/src/data/helper/dataValueHelper.ts
index 1c10798..e63a50d 100644
--- a/src/data/helper/dataValueHelper.ts
+++ b/src/data/helper/dataValueHelper.ts
@@ -19,7 +19,7 @@
 
 import { ParsedValue, DimensionType } from '../../util/types';
 import { parseDate, numericToNumber } from '../../util/number';
-import { createHashMap, trim, hasOwn } from 'zrender/src/core/util';
+import { createHashMap, trim, hasOwn, isString, isNumber } from 'zrender/src/core/util';
 import { throwError } from '../../util/log';
 
 
@@ -51,7 +51,7 @@ export function parseDataValue(
 
     if (dimType === 'time'
         // spead up when using timestamp
-        && typeof value !== 'number'
+        && !isNumber(value)
         && value != null
         && value !== '-'
     ) {
@@ -87,7 +87,7 @@ const valueParserMap = createHashMap<RawValueParser, RawValueParserType>({
         return +parseDate(val);
     },
     'trim': function (val) {
-        return typeof val === 'string' ? trim(val) : val;
+        return isString(val) ? trim(val) : val;
     }
 });
 
@@ -115,7 +115,7 @@ class FilterOrderComparator implements FilterComparator {
     private _rvalFloat: number;
     private _opFn: (lval: unknown, rval: unknown) => boolean;
     constructor(op: OrderRelationOperator, rval: unknown) {
-        if (typeof rval !== 'number') {
+        if (!isNumber(rval)) {
             let errMsg = '';
             if (__DEV__) {
                 errMsg = 'rvalue of "<", ">", "<=", ">=" can only be number in filter.';
@@ -128,7 +128,7 @@ class FilterOrderComparator implements FilterComparator {
     // Performance sensitive.
     evaluate(lval: unknown): boolean {
         // Most cases is 'number', and typeof maybe 10 times faseter than parseFloat.
-        return typeof lval === 'number'
+        return isNumber(lval)
             ? this._opFn(lval, this._rvalFloat)
             : this._opFn(numericToNumber(lval), this._rvalFloat);
     }
@@ -155,10 +155,8 @@ export class SortOrderComparator {
     // Performance sensitive.
     evaluate(lval: unknown, rval: unknown): -1 | 0 | 1 {
         // Most cases is 'number', and typeof maybe 10 times faseter than parseFloat.
-        const lvalTypeof = typeof lval;
-        const rvalTypeof = typeof rval;
-        let lvalFloat = lvalTypeof === 'number' ? lval : numericToNumber(lval);
-        let rvalFloat = rvalTypeof === 'number' ? rval : numericToNumber(rval);
+        let lvalFloat = isNumber(lval) ? lval : numericToNumber(lval);
+        let rvalFloat = isNumber(rval) ? rval : numericToNumber(rval);
         const lvalNotNumeric = isNaN(lvalFloat as number);
         const rvalNotNumeric = isNaN(rvalFloat as number);
 
@@ -169,13 +167,11 @@ export class SortOrderComparator {
             rvalFloat = this._incomparable;
         }
         if (lvalNotNumeric && rvalNotNumeric) {
-            const lvalIsStr = lvalTypeof === 'string';
-            const rvalIsStr = rvalTypeof === 'string';
-            if (lvalIsStr) {
-                lvalFloat = rvalIsStr ? lval : 0;
+            if (isString(lval)) {
+                lvalFloat = isString(rval) ? lval as unknown as number : 0;
             }
-            if (rvalIsStr) {
-                rvalFloat = lvalIsStr ? rval : 0;
+            if (isString(rval)) {
+                rvalFloat = isString(lval) ? rval as unknown as number : 0;
             }
         }
 
diff --git a/src/data/helper/transform.ts b/src/data/helper/transform.ts
index 9abce7e..cfb2b18 100644
--- a/src/data/helper/transform.ts
+++ b/src/data/helper/transform.ts
@@ -26,7 +26,7 @@ import {
 } from '../../util/types';
 import { normalizeToArray } from '../../util/model';
 import {
-    createHashMap, bind, each, hasOwn, map, clone, isObject, extend
+    createHashMap, bind, each, hasOwn, map, clone, isObject, extend, isNumber
 } from 'zrender/src/core/util';
 import {
     getRawSourceItemGetter, getRawSourceDataCounter, getRawSourceValueGetter
@@ -312,7 +312,7 @@ function getDimensionInfo(
         return;
     }
     // Keep the same logic as `List::getDimension` did.
-    if (typeof dim === 'number'
+    if (isNumber(dim)
         // If being a number-like string but not being defined a dimension name.
         || (!isNaN(dim as any) && !hasOwn(dimsByName, dim))
     ) {
diff --git a/src/label/sectorLabel.ts b/src/label/sectorLabel.ts
index 33faf92..7f29392 100644
--- a/src/label/sectorLabel.ts
+++ b/src/label/sectorLabel.ts
@@ -21,7 +21,7 @@
 import {calculateTextPosition, TextPositionCalculationResult} from 'zrender/src/contain/text';
 import { RectLike } from 'zrender/src/core/BoundingRect';
 import {BuiltinTextPosition, TextAlign, TextVerticalAlign} from 'zrender/src/core/types';
-import {isArray} from 'zrender/src/core/util';
+import {isArray, isNumber} from 'zrender/src/core/util';
 import {ElementCalculateTextPosition, ElementTextConfig} from 'zrender/src/Element';
 import { Sector } from '../util/graphic';
 
@@ -195,7 +195,7 @@ export function setSectorTextRotation<T extends (string | (number | string)[])>(
     positionMapping: (seriesLabelPosition: T) => SectorTextPosition,
     rotateType: number | 'auto'
 ) {
-    if (typeof rotateType === 'number') {
+    if (isNumber(rotateType)) {
         // user-set rotation
         sector.setTextConfig({
             rotation: rotateType
diff --git a/src/model/Model.ts b/src/model/Model.ts
index 0a41fc0..3ebffaf 100644
--- a/src/model/Model.ts
+++ b/src/model/Model.ts
@@ -168,47 +168,6 @@ class Model<Opt = ModelOption> {    // TODO: TYPE use unknown instead of any?
     }
 
     /**
-     * Squash option stack into one.
-     * parentModel will be removed after squashed.
-     *
-     * NOTE: resolveParentPath will not be applied here for simplicity. DON'T use this function
-     * if resolveParentPath is modified.
-     *
-     * @param deepMerge If do deep merge. Default to be false.
-     */
-    // squash(
-    //     deepMerge?: boolean,
-    //     handleCallback?: (func: () => object) => object
-    // ) {
-    //     const optionStack = [];
-    //     let model: Model = this;
-    //     while (model) {
-    //         if (model.option) {
-    //             optionStack.push(model.option);
-    //         }
-    //         model = model.parentModel;
-    //     }
-
-    //     const newOption = {} as Opt;
-    //     let option;
-    //     while (option = optionStack.pop()) {    // Top down merge
-    //         if (isFunction(option) && handleCallback) {
-    //             option = handleCallback(option);
-    //         }
-    //         if (deepMerge) {
-    //             merge(newOption, option);
-    //         }
-    //         else {
-    //             extend(newOption, option);
-    //         }
-    //     }
-
-    //     // Remove parentModel
-    //     this.option = newOption;
-    //     this.parentModel = null;
-    // }
-
-    /**
      * If model has option
      */
     isEmpty(): boolean {
diff --git a/src/model/mixin/dataFormat.ts b/src/model/mixin/dataFormat.ts
index 29cab31..87cf12b 100644
--- a/src/model/mixin/dataFormat.ts
+++ b/src/model/mixin/dataFormat.ts
@@ -137,12 +137,12 @@ export class DataFormatMixin {
             );
         }
 
-        if (typeof formatter === 'function') {
+        if (zrUtil.isFunction(formatter)) {
             params.status = status;
             params.dimensionIndex = labelDimIndex;
             return formatter(params);
         }
-        else if (typeof formatter === 'string') {
+        else if (zrUtil.isString(formatter)) {
             const str = formatTpl(formatter, params);
 
             // Support 'aaa{@[3]}bbb{@product}ccc'.
diff --git a/src/processor/dataSample.ts b/src/processor/dataSample.ts
index d492f84..1d19fcd 100644
--- a/src/processor/dataSample.ts
+++ b/src/processor/dataSample.ts
@@ -20,6 +20,7 @@
 import { StageHandler, SeriesOption, SeriesSamplingOptionMixin } from '../util/types';
 import { Dictionary } from 'zrender/src/core/types';
 import SeriesModel from '../model/Series';
+import { isFunction, isString } from 'zrender/src/core/util';
 
 
 type Sampler = (frame: ArrayLike<number>) => number;
@@ -99,10 +100,10 @@ export default function dataSample(seriesType: string): StageHandler {
                         seriesModel.setData(data.lttbDownSample(data.mapDimension(valueAxis.dim), 1 / rate));
                     }
                     let sampler;
-                    if (typeof sampling === 'string') {
+                    if (isString(sampling)) {
                         sampler = samplers[sampling];
                     }
-                    else if (typeof sampling === 'function') {
+                    else if (isFunction(sampling)) {
                         sampler = sampling;
                     }
                     if (sampler) {
diff --git a/src/processor/negativeDataFilter.ts b/src/processor/negativeDataFilter.ts
index f0316a1..9704bd6 100644
--- a/src/processor/negativeDataFilter.ts
+++ b/src/processor/negativeDataFilter.ts
@@ -17,6 +17,7 @@
 * under the License.
 */
 
+import { isNumber } from 'zrender/src/core/util';
 import { StageHandler } from '../util/types';
 
 export default function negativeDataFilter(seriesType: string): StageHandler {
@@ -28,7 +29,7 @@ export default function negativeDataFilter(seriesType: string): StageHandler {
                 // handle negative value condition
                 const valueDim = data.mapDimension('value');
                 const curValue = data.get(valueDim, idx);
-                if (typeof curValue === 'number' && !isNaN(curValue) && curValue < 0) {
+                if (isNumber(curValue) && !isNaN(curValue) && curValue < 0) {
                     return false;
                 }
                 return true;
diff --git a/src/scale/Ordinal.ts b/src/scale/Ordinal.ts
index 13ee2b1..eb532bd 100644
--- a/src/scale/Ordinal.ts
+++ b/src/scale/Ordinal.ts
@@ -37,7 +37,7 @@ import {
     ScaleTick
 } from '../util/types';
 import { CategoryAxisBaseOption } from '../coord/axisCommonTypes';
-import { isArray, map, isObject } from 'zrender/src/core/util';
+import { isArray, map, isObject, isString } from 'zrender/src/core/util';
 
 type OrdinalScaleSetting = {
     ordinalMeta?: OrdinalMeta | CategoryAxisBaseOption['data'];
@@ -130,7 +130,7 @@ class OrdinalScale extends Scale<OrdinalScaleSetting> {
     }
 
     parse(val: OrdinalRawValue | OrdinalNumber): OrdinalNumber {
-        return typeof val === 'string'
+        return isString(val)
             ? this._ordinalMeta.getOrdinal(val)
             // val might be float.
             : Math.round(val);
diff --git a/src/scale/Time.ts b/src/scale/Time.ts
index b64567b..5b09795 100644
--- a/src/scale/Time.ts
+++ b/src/scale/Time.ts
@@ -78,7 +78,7 @@ import {TimeAxisLabelFormatterOption} from '../coord/axisCommonTypes';
 import { warn } from '../util/log';
 import { LocaleOption } from '../core/locale';
 import Model from '../model/Model';
-import { filter, map } from 'zrender/src/core/util';
+import { filter, isNumber, map } from 'zrender/src/core/util';
 
 // FIXME 公用?
 const bisect = function (
@@ -234,7 +234,7 @@ class TimeScale extends IntervalScale<TimeScaleSetting> {
 
     parse(val: number | string | Date): number {
         // val might be float.
-        return typeof val === 'number' ? val : +numberUtil.parseDate(val);
+        return isNumber(val) ? val : +numberUtil.parseDate(val);
     }
 
     contain(val: number): boolean {
diff --git a/src/util/clazz.ts b/src/util/clazz.ts
index 13532ba..c3df60b 100644
--- a/src/util/clazz.ts
+++ b/src/util/clazz.ts
@@ -128,7 +128,7 @@ export function enableClassExtend(rootClz: ExtendableConstructor, mandatoryMetho
 }
 
 function isESClass(fn: unknown): boolean {
-    return typeof fn === 'function'
+    return zrUtil.isFunction(fn)
         && /^class\s/.test(Function.prototype.toString.call(fn));
 }
 
diff --git a/src/util/conditionalExpression.ts b/src/util/conditionalExpression.ts
index 5107ac5..9cbb368 100644
--- a/src/util/conditionalExpression.ts
+++ b/src/util/conditionalExpression.ts
@@ -19,7 +19,7 @@
 
 import { OptionDataValue, DimensionLoose, Dictionary } from './types';
 import {
-    keys, isArray, map, isObject, isString, HashMap, isRegExp, isArrayLike, hasOwn
+    keys, isArray, map, isObject, isString, HashMap, isRegExp, isArrayLike, hasOwn, isNumber
 } from 'zrender/src/core/util';
 import { throwError, makePrintable } from './log';
 import {
@@ -189,8 +189,8 @@ class RegExpEvaluator implements FilterComparator {
 
     evaluate(lVal: unknown): boolean {
         const type = typeof lVal;
-        return type === 'string' ? this._condVal.test(lVal as string)
-            : type === 'number' ? this._condVal.test(lVal + '')
+        return isString(type) ? this._condVal.test(lVal as string)
+            : isNumber(type) ? this._condVal.test(lVal + '')
             : false;
     }
 }
diff --git a/src/util/decal.ts b/src/util/decal.ts
index 632660c..83d6772 100644
--- a/src/util/decal.ts
+++ b/src/util/decal.ts
@@ -21,7 +21,7 @@
 import WeakMap from 'zrender/src/core/WeakMap';
 import { ImagePatternObject, PatternObject, SVGPatternObject } from 'zrender/src/graphic/Pattern';
 import LRU from 'zrender/src/core/LRU';
-import {defaults, map, isArray} from 'zrender/src/core/util';
+import {defaults, map, isArray, isString, isNumber} from 'zrender/src/core/util';
 import {getLeastCommonMultiple} from './number';
 import {createSymbol} from './symbol';
 import ExtensionAPI from '../core/ExtensionAPI';
@@ -101,12 +101,11 @@ export function createOrUpdatePatternFromDecal(
         let isValidKey = true;
         for (let i = 0; i < decalKeys.length; ++i) {
             const value = (decalOpt as any)[decalKeys[i]];
-            const valueType = typeof value;
             if (value != null
                 && !isArray(value)
-                && valueType !== 'string'
-                && valueType !== 'number'
-                && valueType !== 'boolean'
+                && !isString(value)
+                && !isNumber(value)
+                && typeof value !== 'boolean'
             ) {
                 isValidKey = false;
                 break;
@@ -316,13 +315,13 @@ function normalizeSymbolArray(symbol: string | (string | string[])[]): string[][
     if (!symbol || (symbol as string[]).length === 0) {
         return [['rect']];
     }
-    if (typeof symbol === 'string') {
+    if (isString(symbol)) {
         return [[symbol]];
     }
 
     let isAllString = true;
     for (let i = 0; i < symbol.length; ++i) {
-        if (typeof symbol[i] !== 'string') {
+        if (!isString(symbol[i])) {
             isAllString = false;
             break;
         }
@@ -333,7 +332,7 @@ function normalizeSymbolArray(symbol: string | (string | string[])[]): string[][
 
     const result: string[][] = [];
     for (let i = 0; i < symbol.length; ++i) {
-        if (typeof symbol[i] === 'string') {
+        if (isString(symbol[i])) {
             result.push([symbol[i] as string]);
         }
         else {
@@ -353,7 +352,7 @@ function normalizeDashArrayX(dash: DecalDashArrayX): number[][] {
     if (!dash || (dash as number[]).length === 0) {
         return [[0, 0]];
     }
-    if (typeof dash === 'number') {
+    if (isNumber(dash)) {
         const dashValue = Math.ceil(dash);
         return [[dashValue, dashValue]];
     }
@@ -364,7 +363,7 @@ function normalizeDashArrayX(dash: DecalDashArrayX): number[][] {
      */
     let isAllNumber = true;
     for (let i = 0; i < dash.length; ++i) {
-        if (typeof dash[i] !== 'number') {
+        if (!isNumber(dash[i])) {
             isAllNumber = false;
             break;
         }
@@ -375,7 +374,7 @@ function normalizeDashArrayX(dash: DecalDashArrayX): number[][] {
 
     const result: number[][] = [];
     for (let i = 0; i < dash.length; ++i) {
-        if (typeof dash[i] === 'number') {
+        if (isNumber(dash[i])) {
             const dashValue = Math.ceil(dash[i] as number);
             result.push([dashValue, dashValue]);
         }
@@ -404,7 +403,7 @@ function normalizeDashArrayY(dash: DecalDashArrayY): number[] {
     if (!dash || typeof dash === 'object' && dash.length === 0) {
         return [0, 0];
     }
-    if (typeof dash === 'number') {
+    if (isNumber(dash)) {
         const dashValue = Math.ceil(dash);
         return [dashValue, dashValue];
     }
diff --git a/src/util/model.ts b/src/util/model.ts
index 2495723..3fa332a 100644
--- a/src/util/model.ts
+++ b/src/util/model.ts
@@ -27,7 +27,8 @@ import {
     assert,
     isString,
     indexOf,
-    isStringSafe
+    isStringSafe,
+    isNumber
 } from 'zrender/src/core/util';
 import env from 'zrender/src/core/env';
 import GlobalModel from '../model/Global';
@@ -543,10 +544,9 @@ export function convertOptionIdName(idOrName: unknown, defaultValue: string): st
     if (idOrName == null) {
         return defaultValue;
     }
-    const type = typeof idOrName;
-    return type === 'string'
-        ? idOrName as string
-        : (type === 'number' || isStringSafe(idOrName))
+    return isString(idOrName)
+        ? idOrName
+        : (isNumber(idOrName) || isStringSafe(idOrName))
         ? idOrName + ''
         : defaultValue;
 }
@@ -1047,7 +1047,7 @@ export function interpolateRawValues(
         return targetValue;
     }
 
-    if (typeof targetValue === 'number') {
+    if (isNumber(targetValue)) {
         const value = interpolateNumber(
             sourceValue as number || 0,
             targetValue as number,
@@ -1062,7 +1062,7 @@ export function interpolateRawValues(
             : precision as number
         );
     }
-    else if (typeof targetValue === 'string') {
+    else if (isString(targetValue)) {
         return percent < 1 ? sourceValue : targetValue;
     }
     else {
diff --git a/src/util/number.ts b/src/util/number.ts
index 2ec02f3..aab32f1 100644
--- a/src/util/number.ts
+++ b/src/util/number.ts
@@ -118,7 +118,7 @@ export function parsePercent(percent: number | string, all: number): number {
             percent = '100%';
             break;
     }
-    if (typeof percent === 'string') {
+    if (zrUtil.isString(percent)) {
         if (_trim(percent).match(/%$/)) {
             return parseFloat(percent) / 100 * all;
         }
@@ -335,7 +335,7 @@ export function parseDate(value: unknown): Date {
     if (value instanceof Date) {
         return value;
     }
-    else if (typeof value === 'string') {
+    else if (zrUtil.isString(value)) {
         // Different browsers parse date in different way, so we parse it manually.
         // Some other issues:
         // new Date('1970-01-01') is UTC,
@@ -585,7 +585,7 @@ export function numericToNumber(val: unknown): number {
     const valFloat = parseFloat(val as string);
     return (
         valFloat == val // eslint-disable-line eqeqeq
-        && (valFloat !== 0 || typeof val !== 'string' || val.indexOf('x') <= 0) // For case ' 0x0 '.
+        && (valFloat !== 0 || !zrUtil.isString(val) || val.indexOf('x') <= 0) // For case ' 0x0 '.
     ) ? valFloat : NaN;
 }
 
diff --git a/src/util/time.ts b/src/util/time.ts
index 72878a6..89cfc27 100644
--- a/src/util/time.ts
+++ b/src/util/time.ts
@@ -164,11 +164,11 @@ export function leveledFormat(
     isUTC: boolean
 ) {
     let template = null;
-    if (typeof formatter === 'string') {
+    if (zrUtil.isString(formatter)) {
         // Single formatter for all units at all levels
         template = formatter;
     }
-    else if (typeof formatter === 'function') {
+    else if (zrUtil.isFunction(formatter)) {
         // Callback formatter
         template = formatter(tick.value, idx, {
             level: tick.level
@@ -264,7 +264,7 @@ export function getUnitValue(
     unit: TimeUnit,
     isUTC: boolean
 ) : number {
-    const date = typeof value === 'number'
+    const date = zrUtil.isNumber(value)
         ? numberUtil.parseDate(value)
         : value;
     unit = unit || getUnitFromValue(value, isUTC);
diff --git a/src/visual/VisualMapping.ts b/src/visual/VisualMapping.ts
index c6eccff..068dea3 100644
--- a/src/visual/VisualMapping.ts
+++ b/src/visual/VisualMapping.ts
@@ -489,7 +489,7 @@ class VisualMapping<VisualOption
                     // but currently value type can exactly be string or number.
                     // Compromise for numeric-like string (like '12'), especially
                     // in the case that visualMap.categories is ['22', '33'].
-                    || (typeof pieceValue === 'string' && pieceValue === value + '')
+                    || (zrUtil.isString(pieceValue) && pieceValue === value + '')
                 ) {
                     return i;
                 }
diff --git a/src/visual/aria.ts b/src/visual/aria.ts
index 9208248..d176583 100644
--- a/src/visual/aria.ts
+++ b/src/visual/aria.ts
@@ -83,7 +83,7 @@ export default function ariaVisual(ecModel: GlobalModel, api: ExtensionAPI) {
                 if (ecModel.isSeriesFiltered(seriesModel)) {
                     return;
                 }
-                if (typeof seriesModel.enableAriaDecal === 'function') {
+                if (zrUtil.isFunction(seriesModel.enableAriaDecal)) {
                     // Let series define how to use decal palette on data
                     seriesModel.enableAriaDecal();
                     return;
@@ -242,7 +242,7 @@ export default function ariaVisual(ecModel: GlobalModel, api: ExtensionAPI) {
     }
 
     function replace(str: string, keyValues: object) {
-        if (typeof str !== 'string') {
+        if (!zrUtil.isString(str)) {
             return str;
         }
 
diff --git a/src/visual/style.ts b/src/visual/style.ts
index e791189..0a1888f 100644
--- a/src/visual/style.ts
+++ b/src/visual/style.ts
@@ -103,10 +103,10 @@ const seriesStyleTask: StageHandler = {
                 globalStyle[colorKey] = colorPalette;
                 data.setVisual('colorFromPalette', true);
             }
-            globalStyle.fill = (globalStyle.fill === 'auto' || typeof globalStyle.fill === 'function')
+            globalStyle.fill = (globalStyle.fill === 'auto' || isFunction(globalStyle.fill))
                 ? colorPalette
                 : globalStyle.fill;
-            globalStyle.stroke = (globalStyle.stroke === 'auto' || typeof globalStyle.stroke === 'function')
+            globalStyle.stroke = (globalStyle.stroke === 'auto' || isFunction(globalStyle.stroke))
                 ? colorPalette
                 : globalStyle.stroke;
         }

---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org