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 2020/02/20 11:33:40 UTC

[incubator-echarts] branch typescript updated: ts: add types for VisualMapping

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

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


The following commit(s) were added to refs/heads/typescript by this push:
     new 766c6e6  ts: add types for VisualMapping
766c6e6 is described below

commit 766c6e6c7ad6b773946413e248c874acb7b2ffb5
Author: pissang <bm...@gmail.com>
AuthorDate: Thu Feb 20 19:33:01 2020 +0800

    ts: add types for VisualMapping
---
 src/.eslintrc.yaml           |   2 +-
 src/chart/bar.ts             |   2 -
 src/chart/funnel.ts          |   2 -
 src/chart/line.ts            |   2 -
 src/echarts.ts               |   4 +-
 src/util/types.ts            | 124 +++++-
 src/visual/VisualMapping.ts  | 918 +++++++++++++++++++++++--------------------
 src/visual/symbol.ts         |  23 +-
 src/visual/visualDefault.ts  |  11 +-
 src/visual/visualSolution.ts | 161 ++++----
 10 files changed, 733 insertions(+), 516 deletions(-)

diff --git a/src/.eslintrc.yaml b/src/.eslintrc.yaml
index 39534cb..8fb078f 100644
--- a/src/.eslintrc.yaml
+++ b/src/.eslintrc.yaml
@@ -94,7 +94,7 @@ rules:
     new-parens: 2
     no-array-constructor: 2
     no-multi-spaces:
-        - 2
+        - 1
         -
             ignoreEOLComments: true
             exceptions:
diff --git a/src/chart/bar.ts b/src/chart/bar.ts
index 4d8d695..db4bbef 100644
--- a/src/chart/bar.ts
+++ b/src/chart/bar.ts
@@ -17,8 +17,6 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 import * as echarts from '../echarts';
 import * as zrUtil from 'zrender/src/core/util';
 import {layout, largeLayout} from '../layout/barGrid';
diff --git a/src/chart/funnel.ts b/src/chart/funnel.ts
index 0699684..154b40b 100644
--- a/src/chart/funnel.ts
+++ b/src/chart/funnel.ts
@@ -17,8 +17,6 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 import * as echarts from '../echarts';
 
 import './funnel/FunnelSeries';
diff --git a/src/chart/line.ts b/src/chart/line.ts
index a03e720..c0c1e6d 100644
--- a/src/chart/line.ts
+++ b/src/chart/line.ts
@@ -17,8 +17,6 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 import * as echarts from '../echarts';
 
 import './line/LineSeries';
diff --git a/src/echarts.ts b/src/echarts.ts
index 9996dea..a073a31 100644
--- a/src/echarts.ts
+++ b/src/echarts.ts
@@ -55,7 +55,7 @@ import {
     Payload, PayloadItem, ECElement, RendererType, ECEvent,
     ActionHandler, ActionInfo, OptionPreprocessor, PostUpdater,
     LoadingEffect, LoadingEffectCreator, StageHandlerInternal,
-    StageHandlerOverallReset, VisualType, StageHandler,
+    StageHandlerOverallReset, StageHandler,
     ViewRootGroup, DimensionDefinitionLoose, ECEventData, ThemeOption,
     ECOption,
     ECUnitOption,
@@ -2163,7 +2163,7 @@ function normalizeRegister(
     priority: number | StageHandler | StageHandlerOverallReset,
     fn: StageHandler | StageHandlerOverallReset,
     defaultPriority: number,
-    visualType?: VisualType
+    visualType?: StageHandlerInternal['visualType']
 ): void {
     if (isFunction(priority) || isObject(priority)) {
         fn = priority as (StageHandler | StageHandlerOverallReset);
diff --git a/src/util/types.ts b/src/util/types.ts
index 6e7bb35..d5220a3 100644
--- a/src/util/types.ts
+++ b/src/util/types.ts
@@ -161,9 +161,6 @@ export interface PostUpdater {
     (ecModel: GlobalModel, api: ExtensionAPI): void;
 }
 
-export type VisualType = 'layout' | 'visual';
-
-
 export interface StageHandlerReset {
     (seriesModel: SeriesModel, ecModel: GlobalModel, api: ExtensionAPI, payload?: Payload):
         StageHandlerProgressExecutor | StageHandlerProgressExecutor[] | void
@@ -183,7 +180,7 @@ export interface StageHandler {
 
 export interface StageHandlerInternal extends StageHandler {
     uid: string;
-    visualType?: VisualType;
+    visualType?: 'layout' | 'visual';
     // modifyOutputEnd?: boolean;
     __prio: number;
     __raw: StageHandler | StageHandlerOverallReset;
@@ -409,6 +406,7 @@ export interface OptionEncode extends OptionEncodeVisualDimensions {
 export type OptionEncodeValue = DimensionIndex[] | DimensionIndex | DimensionName[] | DimensionName;
 export type EncodeDefaulter = (source: Source, dimCount: number) => OptionEncode;
 
+// TODO: TYPE Different callback param for different series
 export interface DataParamsUserOutput {
     // component main type
     componentType: string;
@@ -478,6 +476,9 @@ export interface LarginOptionMixin {
     largeThreshold?: number
 }
 
+/**
+ * Mixin of option set to control the box layout of each component.
+ */
 export interface BoxLayoutOptionMixin {
     width?: number | string;
     height?: number | string;
@@ -508,19 +509,73 @@ export type AnimationDelayCallbackParam = {
 export type AnimationDurationCallback = (idx: number) => number;
 export type AnimationDelayCallback = (idx: number, params?: AnimationDelayCallbackParam) => number;
 
+/**
+ * Mixin of option set to control the animation of series.
+ */
 export interface AnimationOptionMixin {
+    /**
+     * If enable animation
+     */
     animation?: boolean
+    /**
+     * Disable animation when the number of elements exceeds the threshold
+     */
     animationThreshold?: number
     // For init animation
+    /**
+     * Duration of initialize animation.
+     * Can be a callback to specify duration of each element
+     */
     animationDuration?: number | AnimationDurationCallback
+    /**
+     * Easing of initialize animation
+     */
     animationEasing?: easingType
+    /**
+     * Delay of initialize animation
+     * Can be a callback to specify duration of each element
+     */
     animationDelay?: AnimationDelayCallback
     // For update animation
+    /**
+     * Delay of data update animation.
+     * Can be a callback to specify duration of each element
+     */
     animationDurationUpdate?: number | AnimationDurationCallback
+    /**
+     * Easing of data update animation.
+     */
     animationEasingUpdate?: easingType
+    /**
+     * Delay of data update animation.
+     * Can be a callback to specify duration of each element
+     */
     animationDelayUpdate?: number | AnimationDelayCallback
 }
 
+// TODO: TYPE value type?
+export type SymbolSizeCallback = (rawValue: any, params: DataParamsUserOutput) => number | number[]
+export type SymbolCallback = (rawValue: any, params: DataParamsUserOutput) => string
+/**
+ * Mixin of option set to control the element symbol.
+ * Include type of symbol, and size of symbol.
+ */
+export interface SymbolOptionMixin {
+    /**
+     * type of symbol, like `cirlce`, `rect`, or custom path and image.
+     */
+    symbol?: string | SymbolCallback
+    /**
+     * Size of symbol.
+     */
+    symbolSize?: number | number[] | SymbolSizeCallback
+    symbolKeepAspect?: boolean
+}
+
+/**
+ * ItemStyleOption is a most common used set to config element styles.
+ * It includes both fill and stroke style.
+ */
 export interface ItemStyleOption extends ShadowOptionMixin {
     color?: ZRColor
     borderColor?: string
@@ -529,6 +584,11 @@ export interface ItemStyleOption extends ShadowOptionMixin {
     opacity?: number
 }
 
+/**
+ * ItemStyleOption is a option set to control styles on lines.
+ * Used in the components or series like `line`, `axis`
+ * It includes stroke style.
+ */
 export interface LineStyleOption extends ShadowOptionMixin {
     width?: number
     color?: string
@@ -536,10 +596,56 @@ export interface LineStyleOption extends ShadowOptionMixin {
     type?: ZRLineType
 }
 
+/**
+ * ItemStyleOption is a option set to control styles on an area, like polygon, rectangle.
+ * It only include fill style.
+ */
 export interface AreaStyleOption extends ShadowOptionMixin {
     color?: string
 }
 
+type Arrayable<T extends Dictionary<any>> = { [key in keyof T]: T[key] | T[key][] }
+type Dictionaryable<T extends Dictionary<any>> = { [key in keyof T]: T[key] | Dictionary<T[key]>}
+
+export interface VisualOptionUnit {
+    symbol?: string
+    // TODO Support [number, number]?
+    symbolSize?: number
+    color?: ColorString
+    colorAlpha?: number
+    opacity?: number
+    colorLightness?: number
+    colorSaturation?: number
+    colorHue?: number
+
+    // Not exposed?
+    liftZ?: number
+}
+export type VisualOptionFixed = VisualOptionUnit;
+/**
+ * Option about visual properties used in piecewise mapping
+ * Used in each piece.
+ */
+export type VisualOptionPiecewise = VisualOptionUnit
+/**
+ * Option about visual properties used in linear mapping
+ */
+export type VisualOptionLinear = Arrayable<VisualOptionUnit>
+
+/**
+ * Option about visual properties can be encoded from ordinal categories.
+ * Each value can either be a dictonary to lookup with category name, or
+ * be an array to lookup with category index. In this case the array length should
+ * be same with categories
+ */
+export type VisualOptionCategory = Arrayable<VisualOptionUnit> | Dictionaryable<VisualOptionUnit>
+
+export type VisualOption = VisualOptionFixed | VisualOptionLinear | VisualOptionCategory | VisualOptionPiecewise
+/**
+ * All visual properties can be encoded.
+ */
+export type BuiltinVisualProperty = keyof VisualOptionUnit;
+
 interface TextCommonOption extends ShadowOptionMixin {
     color?: string
     fontStyle?: ZRFontStyle
@@ -557,7 +663,7 @@ interface TextCommonOption extends ShadowOptionMixin {
     }
     borderColor?: string
     borderWidth?: number
-    borderRadius?: number | [number, number, number, number]
+    borderRadius?: number | number[]
     padding?: number | number[]
 
     width?: number | string// Percent
@@ -572,8 +678,14 @@ interface TextCommonOption extends ShadowOptionMixin {
 
     tag?: string
 }
-
+/**
+ * LabelOption is an option set to control the style of labels.
+ * Include color, background, shadow, truncate, rotation, distance, etc..
+ */
 export interface LabelOption extends TextCommonOption {
+    /**
+     * If show label
+     */
     show?: boolean
     // TODO: TYPE More specified 'inside', 'insideTop'....
     position?: string | number[] | string[]
diff --git a/src/visual/VisualMapping.ts b/src/visual/VisualMapping.ts
index 0ceb986..49601e5 100644
--- a/src/visual/VisualMapping.ts
+++ b/src/visual/VisualMapping.ts
@@ -17,244 +17,519 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 import * as zrUtil from 'zrender/src/core/util';
 import * as zrColor from 'zrender/src/tool/color';
 import {linearMap} from '../util/number';
+import { AllPropTypes, Dictionary } from 'zrender/src/core/types';
+import {
+    ColorString,
+    BuiltinVisualProperty,
+    VisualOptionPiecewise,
+    VisualOptionCategory,
+    VisualOptionLinear,
+    VisualOptionUnit,
+    ParsedDataValue
+} from '../util/types';
+
+const each = zrUtil.each;
+const isObject = zrUtil.isObject;
+
+const CATEGORY_DEFAULT_VISUAL_INDEX = -1;
+
+// Type of raw value
+type RawValue = ParsedDataValue
+// Type of mapping visual value
+type VisualValue = AllPropTypes<VisualOptionUnit>
+// Type of value after normalized. 0 - 1
+type NormalizedValue = number
+
+type MappingMethod = 'linear' | 'piecewise' | 'category' | 'fixed';
+
+// May include liftZ. wich is not provided to developers.
+
+interface Normalizer {
+    (this: VisualMapping, value?: RawValue): NormalizedValue
+}
+interface ColorMapper {
+    (this: VisualMapping, value: RawValue | NormalizedValue, isNormalized?: boolean, out?: number[])
+        : ColorString | number[]
+}
+interface DoMap {
+    (this: VisualMapping, normalzied?: NormalizedValue, value?: RawValue): VisualValue
+}
+interface VisualValueGetter {
+    (key: string): VisualValue
+}
+interface VisualValueSetter {
+    (key: string, value: VisualValue): void
+}
+interface VisualHandler {
+    applyVisual(
+        this: VisualMapping,
+        value: RawValue,
+        getter: VisualValueGetter,
+        setter: VisualValueSetter
+    ): void
+
+    _normalizedToVisual: {
+        linear(this: VisualMapping, normalized: NormalizedValue): VisualValue
+        category(this: VisualMapping, normalized: NormalizedValue): VisualValue
+        piecewise(this: VisualMapping, normalzied: NormalizedValue, value: RawValue): VisualValue
+        fixed(this: VisualMapping): VisualValue
+    }
+    /**
+     * Get color mapping for the outside usage.
+     * Currently only used in `color` visual.
+     *
+     * The last parameter out is cached color array.
+     */
+    getColorMapper?: (this: VisualMapping) => ColorMapper
+}
 
-var each = zrUtil.each;
-var isObject = zrUtil.isObject;
+interface VisualMappingPiece {
+    value?: number
+    interval?: [number, number]
+    close?: [0 | 1, 0 | 1]
 
-var CATEGORY_DEFAULT_VISUAL_INDEX = -1;
+    visual?: VisualOptionPiecewise
+}
 
-/**
- * @param {Object} option
- * @param {string} [option.type] See visualHandlers.
- * @param {string} [option.mappingMethod] 'linear' or 'piecewise' or 'category' or 'fixed'
- * @param {Array.<number>=} [option.dataExtent] [minExtent, maxExtent],
- *                                              required when mappingMethod is 'linear'
- * @param {Array.<Object>=} [option.pieceList] [
- *                                             {value: someValue},
- *                                             {interval: [min1, max1], visual: {...}},
- *                                             {interval: [min2, max2]}
- *                                             ],
- *                                            required when mappingMethod is 'piecewise'.
- *                                            Visual for only each piece can be specified.
- * @param {Array.<string|Object>=} [option.categories] ['cate1', 'cate2']
- *                                            required when mappingMethod is 'category'.
- *                                            If no option.categories, categories is set
- *                                            as [0, 1, 2, ...].
- * @param {boolean} [option.loop=false] Whether loop mapping when mappingMethod is 'category'.
- * @param {(Array|Object|*)} [option.visual]  Visual data.
- *                                            when mappingMethod is 'category',
- *                                            visual data can be array or object
- *                                            (like: {cate1: '#222', none: '#fff'})
- *                                            or primary types (which represents
- *                                            defualt category visual), otherwise visual
- *                                            can be array or primary (which will be
- *                                            normalized to array).
- *
- */
-var VisualMapping = function (option) {
-    var mappingMethod = option.mappingMethod;
-    var visualType = option.type;
+export interface VisualMappingOption {
+    type?: BuiltinVisualProperty
+
+    mappingMethod?: MappingMethod
 
     /**
-     * @readOnly
-     * @type {Object}
+     * required when mappingMethod is 'linear'
      */
-    var thisOption = this.option = zrUtil.clone(option);
-
+    dataExtent?: [number, number]
     /**
-     * @readOnly
-     * @type {string}
+     *  required when mappingMethod is 'piecewise'.
+     *  Visual for only each piece can be specified
+     * [
+     *   {value: someValue},
+     *   {interval: [min1, max1], visual: {...}},
+     *   {interval: [min2, max2]}
+     *  ],.
      */
-    this.type = visualType;
-
+    pieceList?: VisualMappingPiece[]
     /**
-     * @readOnly
-     * @type {string}
+     * required when mappingMethod is 'category'. If no option.categories, categories is set as [0, 1, 2, ...].
      */
-    this.mappingMethod = mappingMethod;
-
+    categories?: (string | number)[]
     /**
-     * @private
-     * @type {Function}
+     * Whether loop mapping when mappingMethod is 'category'.
+     * @default false
      */
-    this._normalizeData = normalizers[mappingMethod];
-
-    var visualHandler = visualHandlers[visualType];
-
+    loop?: boolean
     /**
-     * @public
-     * @type {Function}
+     * Visual data
+     * when mappingMethod is 'category', visual data can be array or object
+     * (like: {cate1: '#222', none: '#fff'})
+     * or primary types (which represents default category visual), otherwise visual
+     * can be array or primary (which will be normalized to array).
      */
-    this.applyVisual = visualHandler.applyVisual;
+    visual?: VisualValue[] | Dictionary<VisualValue> | VisualValue
+}
 
+interface VisualMappingInnerPiece extends VisualMappingPiece {
+    originIndex: number
+}
+interface VisualMappingInnerOption extends VisualMappingOption {
+    hasSpecialVisual: boolean
+    pieceList: VisualMappingInnerPiece[]
     /**
-     * @public
-     * @type {Function}
+     * Map to get category index
      */
-    this.getColorMapper = visualHandler.getColorMapper;
-
+    categoryMap: Dictionary<number>
     /**
-     * @private
-     * @type {Function}
+     * Cached parsed rgba array from string to avoid parse every time.
      */
-    this._doMap = visualHandler._doMap[mappingMethod];
+    parsedVisual: number[][]
 
-    if (mappingMethod === 'piecewise') {
-        normalizeVisualRange(thisOption);
-        preprocessForPiecewise(thisOption);
-    }
-    else if (mappingMethod === 'category') {
-        thisOption.categories
-            ? preprocessForSpecifiedCategory(thisOption)
-            // categories is ordinal when thisOption.categories not specified,
-            // which need no more preprocess except normalize visual.
-            : normalizeVisualRange(thisOption, true);
-    }
-    else { // mappingMethod === 'linear' or 'fixed'
-        zrUtil.assert(mappingMethod !== 'linear' || thisOption.dataExtent);
-        normalizeVisualRange(thisOption);
-    }
-};
+    // Have converted primary value to array.
+    visual?: VisualValue[] | Dictionary<VisualValue>
+}
 
-VisualMapping.prototype = {
+class VisualMapping<VisualOption
+    extends VisualOptionPiecewise | VisualOptionCategory | VisualOptionUnit | VisualOptionLinear = {}
+> {
 
-    constructor: VisualMapping,
+    option: VisualMappingInnerOption
 
-    mapValueToVisual: function (value) {
-        var normalized = this._normalizeData(value);
-        return this._doMap(normalized, value);
-    },
+    type: BuiltinVisualProperty
 
-    getNormalizer: function () {
-        return zrUtil.bind(this._normalizeData, this);
-    }
-};
+    mappingMethod: MappingMethod
 
-var visualHandlers = VisualMapping.visualHandlers = {
+    applyVisual: VisualHandler['applyVisual']
 
-    color: {
+    getColorMapper: VisualHandler['getColorMapper']
 
-        applyVisual: makeApplyVisual('color'),
+    _normalizeData: Normalizer
 
-        /**
-         * Create a mapper function
-         * @return {Function}
-         */
-        getColorMapper: function () {
-            var thisOption = this.option;
+    _normalizedToVisual: DoMap
 
-            return zrUtil.bind(
-                thisOption.mappingMethod === 'category'
-                    ? function (value, isNormalized) {
-                        !isNormalized && (value = this._normalizeData(value));
-                        return doMapCategory.call(this, value);
-                    }
-                    : function (value, isNormalized, out) {
-                        // If output rgb array
-                        // which will be much faster and useful in pixel manipulation
-                        var returnRGBArray = !!out;
-                        !isNormalized && (value = this._normalizeData(value));
-                        out = zrColor.fastLerp(value, thisOption.parsedVisual, out);
-                        return returnRGBArray ? out : zrColor.stringify(out, 'rgba');
-                    },
-                this
-            );
-        },
+    constructor(option: VisualMappingOption) {
+        const mappingMethod = option.mappingMethod;
+        const visualType = option.type;
+
+        const thisOption: VisualMappingInnerOption = this.option = zrUtil.clone(option) as VisualMappingInnerOption;
+
+        this.type = visualType;
+        this.mappingMethod = mappingMethod;
+
+        this._normalizeData = normalizers[mappingMethod];
+        const visualHandler = VisualMapping.visualHandlers[visualType];
+
+        this.applyVisual = visualHandler.applyVisual;
+
+        this.getColorMapper = visualHandler.getColorMapper;
 
-        _doMap: {
-            linear: function (normalized) {
-                return zrColor.stringify(
-                    zrColor.fastLerp(normalized, this.option.parsedVisual),
-                    'rgba'
+        this._normalizedToVisual = visualHandler._normalizedToVisual[mappingMethod];
+
+        if (mappingMethod === 'piecewise') {
+            normalizeVisualRange(thisOption);
+            preprocessForPiecewise(thisOption);
+        }
+        else if (mappingMethod === 'category') {
+            thisOption.categories
+                ? preprocessForSpecifiedCategory(thisOption)
+                // categories is ordinal when thisOption.categories not specified,
+                // which need no more preprocess except normalize visual.
+                : normalizeVisualRange(thisOption, true);
+        }
+        else { // mappingMethod === 'linear' or 'fixed'
+            zrUtil.assert(mappingMethod !== 'linear' || thisOption.dataExtent);
+            normalizeVisualRange(thisOption);
+        }
+    }
+
+    mapValueToVisual(value: RawValue): VisualValue {
+        var normalized = this._normalizeData(value);
+        return this._normalizedToVisual(normalized, value);
+    }
+
+    getNormalizer() {
+        return zrUtil.bind(this._normalizeData, this);
+    }
+
+    static visualHandlers: {[key in BuiltinVisualProperty]: VisualHandler} = {
+        color: {
+            applyVisual: makeApplyVisual('color'),
+            getColorMapper: function () {
+                var thisOption = this.option;
+
+                return zrUtil.bind(
+                    thisOption.mappingMethod === 'category'
+                        ? function (
+                            this: VisualMapping,
+                            value: NormalizedValue | RawValue,
+                            isNormalized?: boolean
+                        ): ColorString {
+                            !isNormalized && (value = this._normalizeData(value));
+                            return doMapCategory.call(this, value) as ColorString;
+                        }
+                        : function (
+                            this: VisualMapping,
+                            value: NormalizedValue | RawValue,
+                            isNormalized?: boolean,
+                            out?: number[]
+                        ): number[] | string {
+                            // If output rgb array
+                            // which will be much faster and useful in pixel manipulation
+                            var returnRGBArray = !!out;
+                            !isNormalized && (value = this._normalizeData(value));
+                            out = zrColor.fastLerp(value as NormalizedValue, thisOption.parsedVisual, out);
+                            return returnRGBArray ? out : zrColor.stringify(out, 'rgba');
+                        },
+                    this
                 );
             },
-            category: doMapCategory,
-            piecewise: function (normalized, value) {
-                var result = getSpecifiedVisual.call(this, value);
-                if (result == null) {
-                    result = zrColor.stringify(
+
+            _normalizedToVisual: {
+                linear: function (normalized) {
+                    return zrColor.stringify(
                         zrColor.fastLerp(normalized, this.option.parsedVisual),
                         'rgba'
                     );
-                }
-                return result;
+                },
+                category: doMapCategory,
+                piecewise: function (normalized, value) {
+                    var result = getSpecifiedVisual.call(this, value);
+                    if (result == null) {
+                        result = zrColor.stringify(
+                            zrColor.fastLerp(normalized, this.option.parsedVisual),
+                            'rgba'
+                        );
+                    }
+                    return result;
+                },
+                fixed: doMapFixed
+            }
+        },
+
+        colorHue: makePartialColorVisualHandler(function (color: ColorString, value: number) {
+            return zrColor.modifyHSL(color, value);
+        }),
+
+        colorSaturation: makePartialColorVisualHandler(function (color: ColorString, value: number) {
+            return zrColor.modifyHSL(color, null, value);
+        }),
+
+        colorLightness: makePartialColorVisualHandler(function (color: ColorString, value: number) {
+            return zrColor.modifyHSL(color, null, null, value);
+        }),
+
+        colorAlpha: makePartialColorVisualHandler(function (color: ColorString, value: number) {
+            return zrColor.modifyAlpha(color, value);
+        }),
+
+        opacity: {
+            applyVisual: makeApplyVisual('opacity'),
+            _normalizedToVisual: createNormalizedToNumericVisual([0, 1])
+        },
+
+        liftZ: {
+            applyVisual: makeApplyVisual('liftZ'),
+            _normalizedToVisual: {
+                linear: doMapFixed,
+                category: doMapFixed,
+                piecewise: doMapFixed,
+                fixed: doMapFixed
+            }
+        },
+
+        symbol: {
+            applyVisual: function (value, getter, setter) {
+                var symbolCfg = this.mapValueToVisual(value);
+                setter('symbol', symbolCfg as string);
             },
-            fixed: doMapFixed
+            _normalizedToVisual: {
+                linear: doMapToArray,
+                category: doMapCategory,
+                piecewise: function (normalized, value) {
+                    var result = getSpecifiedVisual.call(this, value);
+                    if (result == null) {
+                        result = doMapToArray.call(this, normalized);
+                    }
+                    return result;
+                },
+                fixed: doMapFixed
+            }
+        },
+
+        symbolSize: {
+            applyVisual: makeApplyVisual('symbolSize'),
+            _normalizedToVisual: createNormalizedToNumericVisual([0, 1])
         }
-    },
+    }
+
+
+    /**
+     * List available visual types.
+     *
+     * @public
+     * @return {Array.<string>}
+     */
+    static listVisualTypes() {
+        return zrUtil.keys(VisualMapping.visualHandlers);
+    }
+
+    // /**
+    //  * @public
+    //  */
+    // static addVisualHandler(name, handler) {
+    //     visualHandlers[name] = handler;
+    // }
 
-    colorHue: makePartialColorVisualHandler(function (color, value) {
-        return zrColor.modifyHSL(color, value);
-    }),
+    /**
+     * @public
+     */
+    static isValidType(visualType: string): boolean {
+        return VisualMapping.visualHandlers.hasOwnProperty(visualType);
+    }
 
-    colorSaturation: makePartialColorVisualHandler(function (color, value) {
-        return zrColor.modifyHSL(color, null, value);
-    }),
+    /**
+     * Convinent method.
+     * Visual can be Object or Array or primary type.
+     */
+    static eachVisual<Ctx, T>(
+        visual: T | T[] | Dictionary<T>,
+        callback: (visual: T, key?: string | number) => void,
+        context?: Ctx
+    ) {
+        if (zrUtil.isObject(visual)) {
+            zrUtil.each(visual as Dictionary<T>, callback, context);
+        }
+        else {
+            callback.call(context, visual);
+        }
+    }
 
-    colorLightness: makePartialColorVisualHandler(function (color, value) {
-        return zrColor.modifyHSL(color, null, null, value);
-    }),
+    static mapVisual<Ctx, T>(visual: T, callback: (visual: T, key?: string | number) => T, context?: Ctx): T
+    static mapVisual<Ctx, T>(visual: T[], callback: (visual: T, key?: string | number) => T[], context?: Ctx): T[]
+    static mapVisual<Ctx, T>(
+        visual: Dictionary<T>,
+        callback: (visual: T, key?: string | number) => Dictionary<T>,
+        context?: Ctx
+    ): Dictionary<T>
+    static mapVisual<Ctx, T>(
+        visual: T | T[] | Dictionary<T>,
+        callback: (visual: T, key?: string | number) => T | T[] | Dictionary<T>,
+        context?: Ctx
+    ) {
+        var isPrimary: boolean;
+        var newVisual: T | T[] | Dictionary<T> = zrUtil.isArray(visual)
+            ? []
+            : zrUtil.isObject(visual)
+            ? {}
+            : (isPrimary = true, null);
+
+        VisualMapping.eachVisual(visual, function (v, key) {
+            var newVal = callback.call(context, v, key);
+            isPrimary ? (newVisual = newVal) : ((newVisual as Dictionary<T>)[key as string] = newVal as T);
+        });
+        return newVisual;
+    }
 
-    colorAlpha: makePartialColorVisualHandler(function (color, value) {
-        return zrColor.modifyAlpha(color, value);
-    }),
+    /**
+     * Retrieve visual properties from given object.
+     */
+    static retrieveVisuals(obj: Dictionary<any>): VisualOptionPiecewise {
+        var ret: VisualOptionPiecewise = {};
+        var hasVisual: boolean;
+
+        obj && each(VisualMapping.visualHandlers, function (h, visualType: BuiltinVisualProperty) {
+            if (obj.hasOwnProperty(visualType)) {
+                (ret as any)[visualType] = obj[visualType];
+                hasVisual = true;
+            }
+        });
 
-    opacity: {
-        applyVisual: makeApplyVisual('opacity'),
-        _doMap: makeDoMap([0, 1])
-    },
+        return hasVisual ? ret : null;
+    }
 
-    liftZ: {
-        applyVisual: makeApplyVisual('liftZ'),
-        _doMap: {
-            linear: doMapFixed,
-            category: doMapFixed,
-            piecewise: doMapFixed,
-            fixed: doMapFixed
+    /**
+     * Give order to visual types, considering colorSaturation, colorAlpha depends on color.
+     *
+     * @public
+     * @param {(Object|Array)} visualTypes If Object, like: {color: ..., colorSaturation: ...}
+     *                                     IF Array, like: ['color', 'symbol', 'colorSaturation']
+     * @return {Array.<string>} Sorted visual types.
+     */
+    static prepareVisualTypes(
+        visualTypes: {[key in BuiltinVisualProperty]?: any} | BuiltinVisualProperty[]
+    ) {
+        if (zrUtil.isArray(visualTypes)) {
+            visualTypes = visualTypes.slice();
+        }
+        else if (isObject(visualTypes)) {
+            var types: BuiltinVisualProperty[] = [];
+            each(visualTypes, function (item: unknown, type: BuiltinVisualProperty) {
+                types.push(type);
+            });
+            visualTypes = types;
+        }
+        else {
+            return [];
         }
-    },
 
-    symbol: {
-        applyVisual: function (value, getter, setter) {
-            var symbolCfg = this.mapValueToVisual(value);
-            if (zrUtil.isString(symbolCfg)) {
-                setter('symbol', symbolCfg);
+        visualTypes.sort(function (type1: BuiltinVisualProperty, type2: BuiltinVisualProperty) {
+            // color should be front of colorSaturation, colorAlpha, ...
+            // symbol and symbolSize do not matter.
+            return (type2 === 'color' && type1 !== 'color' && type1.indexOf('color') === 0)
+                ? 1 : -1;
+        });
+
+        return visualTypes;
+    }
+
+    /**
+     * 'color', 'colorSaturation', 'colorAlpha', ... are depends on 'color'.
+     * Other visuals are only depends on themself.
+     */
+    static dependsOn(visualType1: BuiltinVisualProperty, visualType2: BuiltinVisualProperty) {
+        return visualType2 === 'color'
+            ? !!(visualType1 && visualType1.indexOf(visualType2) === 0)
+            : visualType1 === visualType2;
+    }
+
+    /**
+     * @param value
+     * @param pieceList [{value: ..., interval: [min, max]}, ...]
+     *                         Always from small to big.
+     * @param findClosestWhenOutside Default to be false
+     * @return index
+     */
+    static findPieceIndex(value: number, pieceList: VisualMappingPiece[], findClosestWhenOutside?: boolean): number {
+        var possibleI: number;
+        var abs = Infinity;
+
+        // value has the higher priority.
+        for (var i = 0, len = pieceList.length; i < len; i++) {
+            var pieceValue = pieceList[i].value;
+            if (pieceValue != null) {
+                if (pieceValue === value
+                    // FIXME
+                    // It is supposed to compare value according to value type of dimension,
+                    // 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 + '')
+                ) {
+                    return i;
+                }
+                findClosestWhenOutside && updatePossible(pieceValue, i);
             }
-            else if (isObject(symbolCfg)) {
-                for (var name in symbolCfg) {
-                    if (symbolCfg.hasOwnProperty(name)) {
-                        setter(name, symbolCfg[name]);
+        }
+
+        for (var i = 0, len = pieceList.length; i < len; i++) {
+            var piece = pieceList[i];
+            var interval = piece.interval;
+            var close = piece.close;
+
+            if (interval) {
+                if (interval[0] === -Infinity) {
+                    if (littleThan(close[1], value, interval[1])) {
+                        return i;
                     }
                 }
-            }
-        },
-        _doMap: {
-            linear: doMapToArray,
-            category: doMapCategory,
-            piecewise: function (normalized, value) {
-                var result = getSpecifiedVisual.call(this, value);
-                if (result == null) {
-                    result = doMapToArray.call(this, normalized);
+                else if (interval[1] === Infinity) {
+                    if (littleThan(close[0], interval[0], value)) {
+                        return i;
+                    }
                 }
-                return result;
-            },
-            fixed: doMapFixed
+                else if (
+                    littleThan(close[0], interval[0], value)
+                    && littleThan(close[1], value, interval[1])
+                ) {
+                    return i;
+                }
+                findClosestWhenOutside && updatePossible(interval[0], i);
+                findClosestWhenOutside && updatePossible(interval[1], i);
+            }
         }
-    },
 
-    symbolSize: {
-        applyVisual: makeApplyVisual('symbolSize'),
-        _doMap: makeDoMap([0, 1])
-    }
-};
+        if (findClosestWhenOutside) {
+            return value === Infinity
+                ? pieceList.length - 1
+                : value === -Infinity
+                ? 0
+                : possibleI;
+        }
 
+        function updatePossible(val: number, index: number) {
+            var newAbs = Math.abs(val - value);
+            if (newAbs < abs) {
+                abs = newAbs;
+                possibleI = index;
+            }
+        }
 
-function preprocessForPiecewise(thisOption) {
+    }
+}
+
+function preprocessForPiecewise(thisOption: VisualMappingInnerOption) {
     var pieceList = thisOption.pieceList;
     thisOption.hasSpecialVisual = false;
 
@@ -268,19 +543,19 @@ function preprocessForPiecewise(thisOption) {
     });
 }
 
-function preprocessForSpecifiedCategory(thisOption) {
+function preprocessForSpecifiedCategory(thisOption: VisualMappingInnerOption) {
     // Hash categories.
-    var categories = thisOption.categories;
-    var visual = thisOption.visual;
+    const categories = thisOption.categories;
+    const categoryMap: VisualMappingInnerOption['categoryMap'] = thisOption.categoryMap = {};
 
-    var categoryMap = thisOption.categoryMap = {};
+    let visual = thisOption.visual;
     each(categories, function (cate, index) {
         categoryMap[cate] = index;
     });
 
     // Process visual map input.
     if (!zrUtil.isArray(visual)) {
-        var visualArr = [];
+        var visualArr: VisualValue[] = [];
 
         if (zrUtil.isObject(visual)) {
             each(visual, function (v, cate) {
@@ -305,9 +580,9 @@ function preprocessForSpecifiedCategory(thisOption) {
     }
 }
 
-function normalizeVisualRange(thisOption, isCategory) {
+function normalizeVisualRange(thisOption: VisualMappingInnerOption, isCategory?: boolean) {
     var visual = thisOption.visual;
-    var visualArr = [];
+    var visualArr: VisualValue[] = [];
 
     if (zrUtil.isObject(visual)) {
         each(visual, function (v) {
@@ -331,32 +606,35 @@ function normalizeVisualRange(thisOption, isCategory) {
     setVisualToOption(thisOption, visualArr);
 }
 
-function makePartialColorVisualHandler(applyValue) {
+function makePartialColorVisualHandler(
+    applyValue: (prop: VisualValue, value: NormalizedValue) => VisualValue
+): VisualHandler {
     return {
         applyVisual: function (value, getter, setter) {
-            value = this.mapValueToVisual(value);
+            // Only used in HSL
+            const colorChannel = this.mapValueToVisual(value);
             // Must not be array value
-            setter('color', applyValue(getter('color'), value));
+            setter('color', applyValue(getter('color'), colorChannel as number));
         },
-        _doMap: makeDoMap([0, 1])
+        _normalizedToVisual: createNormalizedToNumericVisual([0, 1])
     };
 }
 
-function doMapToArray(normalized) {
-    var visual = this.option.visual;
+function doMapToArray(this: VisualMapping<VisualOptionLinear>, normalized: NormalizedValue): VisualValue {
+    var visual = this.option.visual as VisualValue[];
     return visual[
         Math.round(linearMap(normalized, [0, 1], [0, visual.length - 1], true))
-    ] || {};
+    ] || {} as any;    // TODO {}?
 }
 
-function makeApplyVisual(visualType) {
+function makeApplyVisual(visualType: string): VisualHandler['applyVisual'] {
     return function (value, getter, setter) {
         setter(visualType, this.mapValueToVisual(value));
     };
 }
 
-function doMapCategory(normalized) {
-    var visual = this.option.visual;
+function doMapCategory(this: VisualMapping<VisualOptionCategory>, normalized: NormalizedValue): VisualValue {
+    var visual = this.option.visual as Dictionary<any>;
     return visual[
         (this.option.loop && normalized !== CATEGORY_DEFAULT_VISUAL_INDEX)
             ? normalized % visual.length
@@ -364,20 +642,24 @@ function doMapCategory(normalized) {
     ];
 }
 
-function doMapFixed() {
-    return this.option.visual[0];
+function doMapFixed(this: VisualMapping): VisualValue {
+    // visual will be convert to array.
+    return (this.option.visual as VisualValue[])[0];
 }
 
-function makeDoMap(sourceExtent) {
+/**
+ * Create mapped to numeric visual
+ */
+function createNormalizedToNumericVisual(sourceExtent: [number, number]): VisualHandler['_normalizedToVisual'] {
     return {
         linear: function (normalized) {
-            return linearMap(normalized, sourceExtent, this.option.visual, true);
+            return linearMap(normalized, sourceExtent, this.option.visual as [number, number], true);
         },
         category: doMapCategory,
         piecewise: function (normalized, value) {
             var result = getSpecifiedVisual.call(this, value);
             if (result == null) {
-                result = linearMap(normalized, sourceExtent, this.option.visual, true);
+                result = linearMap(normalized, sourceExtent, this.option.visual as [number, number], true);
             }
             return result;
         },
@@ -385,7 +667,7 @@ function makeDoMap(sourceExtent) {
     };
 }
 
-function getSpecifiedVisual(value) {
+function getSpecifiedVisual(this: VisualMapping, value: number) {
     var thisOption = this.option;
     var pieceList = thisOption.pieceList;
     if (thisOption.hasSpecialVisual) {
@@ -397,10 +679,10 @@ function getSpecifiedVisual(value) {
     }
 }
 
-function setVisualToOption(thisOption, visualArr) {
+function setVisualToOption(thisOption: VisualMappingInnerOption, visualArr: VisualValue[]) {
     thisOption.visual = visualArr;
     if (thisOption.type === 'color') {
-        thisOption.parsedVisual = zrUtil.map(visualArr, function (item) {
+        thisOption.parsedVisual = zrUtil.map(visualArr, function (item: string) {
             return zrColor.parse(item);
         });
     }
@@ -411,233 +693,31 @@ function setVisualToOption(thisOption, visualArr) {
 /**
  * Normalizers by mapping methods.
  */
-var normalizers = {
-
-    linear: function (value) {
-        return linearMap(value, this.option.dataExtent, [0, 1], true);
+const normalizers: { [key in MappingMethod]: Normalizer } = {
+    linear: function (value: RawValue): NormalizedValue {
+        return linearMap(value as number, this.option.dataExtent, [0, 1], true);
     },
 
-    piecewise: function (value) {
+    piecewise: function (value: RawValue): NormalizedValue {
         var pieceList = this.option.pieceList;
-        var pieceIndex = VisualMapping.findPieceIndex(value, pieceList, true);
+        var pieceIndex = VisualMapping.findPieceIndex(value as number, pieceList, true);
         if (pieceIndex != null) {
             return linearMap(pieceIndex, [0, pieceList.length - 1], [0, 1], true);
         }
     },
 
-    category: function (value) {
-        var index = this.option.categories
+    category: function (value: RawValue): NormalizedValue {
+        const index: number = this.option.categories
             ? this.option.categoryMap[value]
-            : value; // ordinal
+            : value as number; // ordinal value
         return index == null ? CATEGORY_DEFAULT_VISUAL_INDEX : index;
     },
 
-    fixed: zrUtil.noop
+    fixed: zrUtil.noop as Normalizer
 };
 
 
-
-/**
- * List available visual types.
- *
- * @public
- * @return {Array.<string>}
- */
-VisualMapping.listVisualTypes = function () {
-    var visualTypes = [];
-    zrUtil.each(visualHandlers, function (handler, key) {
-        visualTypes.push(key);
-    });
-    return visualTypes;
-};
-
-/**
- * @public
- */
-VisualMapping.addVisualHandler = function (name, handler) {
-    visualHandlers[name] = handler;
-};
-
-/**
- * @public
- */
-VisualMapping.isValidType = function (visualType) {
-    return visualHandlers.hasOwnProperty(visualType);
-};
-
-/**
- * Convinent method.
- * Visual can be Object or Array or primary type.
- *
- * @public
- */
-VisualMapping.eachVisual = function (visual, callback, context) {
-    if (zrUtil.isObject(visual)) {
-        zrUtil.each(visual, callback, context);
-    }
-    else {
-        callback.call(context, visual);
-    }
-};
-
-VisualMapping.mapVisual = function (visual, callback, context) {
-    var isPrimary;
-    var newVisual = zrUtil.isArray(visual)
-        ? []
-        : zrUtil.isObject(visual)
-        ? {}
-        : (isPrimary = true, null);
-
-    VisualMapping.eachVisual(visual, function (v, key) {
-        var newVal = callback.call(context, v, key);
-        isPrimary ? (newVisual = newVal) : (newVisual[key] = newVal);
-    });
-    return newVisual;
-};
-
-/**
- * @public
- * @param {Object} obj
- * @return {Object} new object containers visual values.
- *                 If no visuals, return null.
- */
-VisualMapping.retrieveVisuals = function (obj) {
-    var ret = {};
-    var hasVisual;
-
-    obj && each(visualHandlers, function (h, visualType) {
-        if (obj.hasOwnProperty(visualType)) {
-            ret[visualType] = obj[visualType];
-            hasVisual = true;
-        }
-    });
-
-    return hasVisual ? ret : null;
-};
-
-/**
- * Give order to visual types, considering colorSaturation, colorAlpha depends on color.
- *
- * @public
- * @param {(Object|Array)} visualTypes If Object, like: {color: ..., colorSaturation: ...}
- *                                     IF Array, like: ['color', 'symbol', 'colorSaturation']
- * @return {Array.<string>} Sorted visual types.
- */
-VisualMapping.prepareVisualTypes = function (visualTypes) {
-    if (isObject(visualTypes)) {
-        var types = [];
-        each(visualTypes, function (item, type) {
-            types.push(type);
-        });
-        visualTypes = types;
-    }
-    else if (zrUtil.isArray(visualTypes)) {
-        visualTypes = visualTypes.slice();
-    }
-    else {
-        return [];
-    }
-
-    visualTypes.sort(function (type1, type2) {
-        // color should be front of colorSaturation, colorAlpha, ...
-        // symbol and symbolSize do not matter.
-        return (type2 === 'color' && type1 !== 'color' && type1.indexOf('color') === 0)
-            ? 1 : -1;
-    });
-
-    return visualTypes;
-};
-
-/**
- * 'color', 'colorSaturation', 'colorAlpha', ... are depends on 'color'.
- * Other visuals are only depends on themself.
- *
- * @public
- * @param {string} visualType1
- * @param {string} visualType2
- * @return {boolean}
- */
-VisualMapping.dependsOn = function (visualType1, visualType2) {
-    return visualType2 === 'color'
-        ? !!(visualType1 && visualType1.indexOf(visualType2) === 0)
-        : visualType1 === visualType2;
-};
-
-/**
- * @param {number} value
- * @param {Array.<Object>} pieceList [{value: ..., interval: [min, max]}, ...]
- *                         Always from small to big.
- * @param {boolean} [findClosestWhenOutside=false]
- * @return {number} index
- */
-VisualMapping.findPieceIndex = function (value, pieceList, findClosestWhenOutside) {
-    var possibleI;
-    var abs = Infinity;
-
-    // value has the higher priority.
-    for (var i = 0, len = pieceList.length; i < len; i++) {
-        var pieceValue = pieceList[i].value;
-        if (pieceValue != null) {
-            if (pieceValue === value
-                // FIXME
-                // It is supposed to compare value according to value type of dimension,
-                // 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 + '')
-            ) {
-                return i;
-            }
-            findClosestWhenOutside && updatePossible(pieceValue, i);
-        }
-    }
-
-    for (var i = 0, len = pieceList.length; i < len; i++) {
-        var piece = pieceList[i];
-        var interval = piece.interval;
-        var close = piece.close;
-
-        if (interval) {
-            if (interval[0] === -Infinity) {
-                if (littleThan(close[1], value, interval[1])) {
-                    return i;
-                }
-            }
-            else if (interval[1] === Infinity) {
-                if (littleThan(close[0], interval[0], value)) {
-                    return i;
-                }
-            }
-            else if (
-                littleThan(close[0], interval[0], value)
-                && littleThan(close[1], value, interval[1])
-            ) {
-                return i;
-            }
-            findClosestWhenOutside && updatePossible(interval[0], i);
-            findClosestWhenOutside && updatePossible(interval[1], i);
-        }
-    }
-
-    if (findClosestWhenOutside) {
-        return value === Infinity
-            ? pieceList.length - 1
-            : value === -Infinity
-            ? 0
-            : possibleI;
-    }
-
-    function updatePossible(val, index) {
-        var newAbs = Math.abs(val - value);
-        if (newAbs < abs) {
-            abs = newAbs;
-            possibleI = index;
-        }
-    }
-
-};
-
-function littleThan(close, a, b) {
+function littleThan(close: boolean | 0 | 1, a: number, b: number): boolean {
     return close ? a <= b : a < b;
 }
 
diff --git a/src/visual/symbol.ts b/src/visual/symbol.ts
index 04af7fd..cd0bb05 100644
--- a/src/visual/symbol.ts
+++ b/src/visual/symbol.ts
@@ -17,11 +17,13 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 import {isFunction} from 'zrender/src/core/util';
+import { StageHandler, SeriesOption, SymbolOptionMixin, SymbolSizeCallback, SymbolCallback } from '../util/types';
+import List from '../data/List';
+import SeriesModel from '../model/Series';
+import GlobalModel from '../model/Global';
 
-export default function (seriesType, defaultSymbolType, legendSymbol) {
+export default function (seriesType: string, defaultSymbolType: string, legendSymbol: string): StageHandler {
     // Encoding visual for all series include which is filtered for legend drawing
     return {
         seriesType: seriesType,
@@ -29,7 +31,10 @@ export default function (seriesType, defaultSymbolType, legendSymbol) {
         // For legend.
         performRawSeries: true,
 
-        reset: function (seriesModel, ecModel, api) {
+        reset: function (
+            seriesModel: SeriesModel<SeriesOption & SymbolOptionMixin>,
+            ecModel: GlobalModel
+        ) {
             var data = seriesModel.getData();
 
             var symbolType = seriesModel.get('symbol');
@@ -58,12 +63,16 @@ export default function (seriesType, defaultSymbolType, legendSymbol) {
                 return;
             }
 
-            function dataEach(data, idx) {
+            function dataEach(data: List, idx: number) {
                 if (hasCallback) {
                     var rawValue = seriesModel.getRawValue(idx);
                     var params = seriesModel.getDataParams(idx);
-                    hasSymbolTypeCallback && data.setItemVisual(idx, 'symbol', symbolType(rawValue, params));
-                    hasSymbolSizeCallback && data.setItemVisual(idx, 'symbolSize', symbolSize(rawValue, params));
+                    hasSymbolTypeCallback && data.setItemVisual(
+                        idx, 'symbol', (symbolType as SymbolCallback)(rawValue, params)
+                    );
+                    hasSymbolSizeCallback && data.setItemVisual(
+                        idx, 'symbolSize', (symbolSize as SymbolSizeCallback)(rawValue, params)
+                    );
                 }
 
                 if (data.hasItemOption) {
diff --git a/src/visual/visualDefault.ts b/src/visual/visualDefault.ts
index a3067e4..ac1ad54 100644
--- a/src/visual/visualDefault.ts
+++ b/src/visual/visualDefault.ts
@@ -17,8 +17,6 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 /**
  * @file Visual mapping.
  */
@@ -26,11 +24,10 @@
 import * as zrUtil from 'zrender/src/core/util';
 
 var visualDefault = {
-
     /**
      * @public
      */
-    get: function (visualType, key, isCategory) {
+    get: function (visualType: string, key: 'active' | 'inactive', isCategory?: boolean) {
         var value = zrUtil.clone(
             (defaultOption[visualType] || {})[key]
         );
@@ -39,10 +36,12 @@ var visualDefault = {
             ? (zrUtil.isArray(value) ? value[value.length - 1] : value)
             : value;
     }
-
 };
 
-var defaultOption = {
+var defaultOption: {[key: string]: {
+    active: string[] | number[]
+    inactive: string[] | number[]
+}} = {
 
     color: {
         active: ['#006edd', '#e0ffff'],
diff --git a/src/visual/visualSolution.ts b/src/visual/visualSolution.ts
index 66341af..b62775a 100644
--- a/src/visual/visualSolution.ts
+++ b/src/visual/visualSolution.ts
@@ -17,18 +17,29 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 /**
  * @file Visual solution, for consistent option specification.
  */
 
 import * as zrUtil from 'zrender/src/core/util';
-import VisualMapping from './VisualMapping';
+import VisualMapping, { VisualMappingOption } from './VisualMapping';
+import { Dictionary } from 'zrender/src/core/types';
+import {
+    VisualOption,
+    BuiltinVisualProperty,
+    ParsedDataValue,
+    DimensionLoose,
+    StageHandlerProgressExecutor
+} from '../util/types';
+import List from '../data/List';
 
 var each = zrUtil.each;
 
-function hasKeys(obj) {
+type WithKey<T extends string, S> = { [key in T]?: S}
+type VisualMappingCollection<VisualState extends string>
+    = WithKey<VisualState, WithKey<BuiltinVisualProperty, VisualMapping>>
+
+function hasKeys(obj: Dictionary<any>) {
     if (obj) {
         for (var name in obj) {
             if (obj.hasOwnProperty(name)) {
@@ -38,19 +49,17 @@ function hasKeys(obj) {
     }
 }
 
-/**
- * @param {Object} option
- * @param {Array.<string>} stateList
- * @param {Function} [supplementVisualOption]
- * @return {Object} visualMappings <state, <visualType, module:echarts/visual/VisualMapping>>
- */
-export function createVisualMappings(option, stateList, supplementVisualOption) {
-    var visualMappings = {};
+export function createVisualMappings<VisualState extends string>(
+    option: Dictionary<VisualOption>,
+    stateList: readonly VisualState[],
+    supplementVisualOption: (mappingOption: VisualMappingOption, state: string) => void
+) {
+    var visualMappings: VisualMappingCollection<VisualState> = {};
 
     each(stateList, function (state) {
         var mappings = visualMappings[state] = createMappings();
 
-        each(option[state], function (visualData, visualType) {
+        each(option[state], function (visualData, visualType: BuiltinVisualProperty) {
             if (!VisualMapping.isValidType(visualType)) {
                 return;
             }
@@ -78,17 +87,14 @@ export function createVisualMappings(option, stateList, supplementVisualOption)
         // Make sure hidden fields will not be visited by
         // object iteration (with hasOwnProperty checking).
         Creater.prototype.__hidden = Creater.prototype;
-        var obj = new Creater();
+        var obj = new (Creater as any)();
         return obj;
     }
 }
 
-/**
- * @param {Object} thisOption
- * @param {Object} newOption
- * @param {Array.<string>} keys
- */
-export function replaceVisualOption(thisOption, newOption, keys) {
+export function replaceVisualOption<T extends string>(
+    thisOption: WithKey<T, any>, newOption: WithKey<T, any>, keys: readonly T[]
+) {
     // Visual attributes merge is not supported, otherwise it
     // brings overcomplicated merge logic. See #2853. So if
     // newOption has anyone of these keys, all of these keys
@@ -110,28 +116,35 @@ export function replaceVisualOption(thisOption, newOption, keys) {
 }
 
 /**
- * @param {Array.<string>} stateList
- * @param {Object} visualMappings <state, Object.<visualType, module:echarts/visual/VisualMapping>>
- * @param {module:echarts/data/List} list
- * @param {Function} getValueState param: valueOrIndex, return: state.
- * @param {object} [scope] Scope for getValueState
- * @param {string} [dimension] Concrete dimension, if used.
+ * @param stateList
+ * @param visualMappings
+ * @param list
+ * @param getValueState param: valueOrIndex, return: state.
+ * @param scope Scope for getValueState
+ * @param dimension Concrete dimension, if used.
  */
 // ???! handle brush?
-export function applyVisual(stateList, visualMappings, data, getValueState, scope, dimension) {
-    var visualTypesMap = {};
+export function applyVisual<VisualState extends string, Scope>(
+    stateList: VisualState[],
+    visualMappings: VisualMappingCollection<VisualState>,
+    data: List,
+    getValueState: (this: Scope, valueOrIndex: ParsedDataValue | number) => VisualState,
+    scope?: Scope,
+    dimension?: DimensionLoose
+) {
+    var visualTypesMap: WithKey<VisualState, BuiltinVisualProperty[]> = {};
     zrUtil.each(stateList, function (state) {
         var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]);
         visualTypesMap[state] = visualTypes;
     });
 
-    var dataIndex;
+    var dataIndex: number;
 
-    function getVisual(key) {
+    function getVisual(key: string) {
         return data.getItemVisual(dataIndex, key);
     }
 
-    function setVisual(key, value) {
+    function setVisual(key: string, value: any) {
         data.setItemVisual(dataIndex, key, value);
     }
 
@@ -142,11 +155,14 @@ export function applyVisual(stateList, visualMappings, data, getValueState, scop
         data.each([dimension], eachItem);
     }
 
-    function eachItem(valueOrIndex, index) {
-        dataIndex = dimension == null ? valueOrIndex : index;
+    function eachItem(valueOrIndex: ParsedDataValue | number, index?: number) {
+        dataIndex = dimension == null
+            ? valueOrIndex as number    // First argument is index
+            : index;
 
         var rawDataItem = data.getRawDataItem(dataIndex);
         // Consider performance
+        // @ts-ignore
         if (rawDataItem && rawDataItem.visualMap === false) {
             return;
         }
@@ -165,55 +181,62 @@ export function applyVisual(stateList, visualMappings, data, getValueState, scop
 }
 
 /**
- * @param {module:echarts/data/List} data
- * @param {Array.<string>} stateList
- * @param {Object} visualMappings <state, Object.<visualType, module:echarts/visual/VisualMapping>>
- * @param {Function} getValueState param: valueOrIndex, return: state.
- * @param {number} [dim] dimension or dimension index.
+ * @param data
+ * @param stateList
+ * @param visualMappings <state, Object.<visualType, module:echarts/visual/VisualMapping>>
+ * @param getValueState param: valueOrIndex, return: state.
+ * @param dim dimension or dimension index.
  */
-export function incrementalApplyVisual(stateList, visualMappings, getValueState, dim) {
-    var visualTypesMap = {};
+export function incrementalApplyVisual<VisualState extends string>(
+    stateList: VisualState[],
+    visualMappings: VisualMappingCollection<VisualState>,
+    getValueState: (valueOrIndex: ParsedDataValue | number) => VisualState,
+    dim?: DimensionLoose
+): StageHandlerProgressExecutor {
+    var visualTypesMap: WithKey<VisualState, BuiltinVisualProperty[]> = {};
     zrUtil.each(stateList, function (state) {
         var visualTypes = VisualMapping.prepareVisualTypes(visualMappings[state]);
         visualTypesMap[state] = visualTypes;
     });
 
-    function progress(params, data) {
-        if (dim != null) {
-            dim = data.getDimension(dim);
-        }
+    return {
+        progress: function progress(params, data) {
+            let dimName: string;
+            if (dim != null) {
+                dimName = data.getDimension(dim);
+            }
 
-        function getVisual(key) {
-            return data.getItemVisual(dataIndex, key);
-        }
+            function getVisual(key: string) {
+                return data.getItemVisual(dataIndex, key);
+            }
 
-        function setVisual(key, value) {
-            data.setItemVisual(dataIndex, key, value);
-        }
+            function setVisual(key: string, value: any) {
+                data.setItemVisual(dataIndex, key, value);
+            }
 
-        var dataIndex;
-        while ((dataIndex = params.next()) != null) {
-            var rawDataItem = data.getRawDataItem(dataIndex);
+            var dataIndex: number;
+            while ((dataIndex = params.next()) != null) {
+                var rawDataItem = data.getRawDataItem(dataIndex);
 
-            // Consider performance
-            if (rawDataItem && rawDataItem.visualMap === false) {
-                continue;
-            }
+                // Consider performance
+                // @ts-ignore
+                if (rawDataItem && rawDataItem.visualMap === false) {
+                    continue;
+                }
 
-            var value = dim != null
-                ? data.get(dim, dataIndex, true)
-                : dataIndex;
+                var value = dim != null
+                    ? data.get(dimName, dataIndex)
+                    : dataIndex;
 
-            var valueState = getValueState(value);
-            var mappings = visualMappings[valueState];
-            var visualTypes = visualTypesMap[valueState];
+                var valueState = getValueState(value);
+                var mappings = visualMappings[valueState];
+                var visualTypes = visualTypesMap[valueState];
 
-            for (var i = 0, len = visualTypes.length; i < len; i++) {
-                var type = visualTypes[i];
-                mappings[type] && mappings[type].applyVisual(value, getVisual, setVisual);
+                for (var i = 0, len = visualTypes.length; i < len; i++) {
+                    var type = visualTypes[i];
+                    mappings[type] && mappings[type].applyVisual(value, getVisual, setVisual);
+                }
             }
         }
-    }
-
-    return {progress: progress};
+    };
 }


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