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/03/14 14:31:09 UTC

[incubator-echarts] branch typescript updated: ts: add types for marker. more strict makeInner type. add isCoordinateSystemType

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 b49ce0d  ts: add types for marker. more strict makeInner type. add isCoordinateSystemType
b49ce0d is described below

commit b49ce0d3b615d103b3d2b56e052cadfc7e198924
Author: pissang <bm...@gmail.com>
AuthorDate: Sat Mar 14 22:30:29 2020 +0800

    ts: add types for marker. more strict makeInner type. add isCoordinateSystemType
---
 src/chart/bar/BarView.ts                     |   8 +-
 src/chart/heatmap/HeatmapView.ts             |  14 +-
 src/chart/helper/SymbolDraw.ts               |   2 +-
 src/chart/lines/LinesSeries.ts               |  12 +-
 src/component/axis/axisSplitHelper.ts        |   3 +-
 src/component/axisPointer/BaseAxisPointer.ts |   2 +-
 src/component/axisPointer/axisTrigger.ts     |   3 +-
 src/component/axisPointer/globalListener.ts  |   2 +-
 src/component/dataZoom/DataZoomModel.ts      |   2 -
 src/component/dataZoom/history.ts            |   2 +-
 src/component/dataZoom/roams.ts              |   2 +-
 src/component/marker/MarkAreaModel.ts        |  77 ++++++-
 src/component/marker/MarkAreaView.ts         | 208 +++++++++++--------
 src/component/marker/MarkLineModel.ts        | 106 +++++++++-
 src/component/marker/MarkLineView.ts         | 292 ++++++++++++++++-----------
 src/component/marker/MarkPointModel.ts       |  64 +++++-
 src/component/marker/MarkPointView.ts        | 103 +++++-----
 src/component/marker/MarkerModel.ts          | 166 +++++++++++----
 src/component/marker/MarkerView.ts           |  67 ++++--
 src/component/marker/markerHelper.ts         | 117 ++++++-----
 src/component/visualMap/VisualMapModel.ts    |   2 -
 src/coord/CoordinateSystem.ts                |   6 +
 src/coord/axisCommonTypes.ts                 |   2 +-
 src/coord/geo/geoJSONLoader.ts               |   2 +-
 src/coord/geo/geoSVGLoader.ts                |   2 +-
 src/coord/polar/AngleAxis.ts                 |   2 +-
 src/data/DataDimensionInfo.ts                |   2 +-
 src/data/List.ts                             |  12 +-
 src/model/Component.ts                       |   2 +-
 src/model/Model.ts                           |   4 +-
 src/model/Series.ts                          |   7 +-
 src/model/mixin/colorPalette.ts              |   2 +-
 src/util/graphic.ts                          |   2 +-
 src/util/model.ts                            |  12 +-
 src/util/types.ts                            |  10 +
 src/view/Chart.ts                            |   2 +-
 src/view/Component.ts                        |  33 +--
 37 files changed, 906 insertions(+), 450 deletions(-)

diff --git a/src/chart/bar/BarView.ts b/src/chart/bar/BarView.ts
index 08e5ea7..602bc5c 100644
--- a/src/chart/bar/BarView.ts
+++ b/src/chart/bar/BarView.ts
@@ -37,6 +37,7 @@ import type Axis2D from '../../coord/cartesian/Axis2D';
 import type Cartesian2D from '../../coord/cartesian/Cartesian2D';
 import type { RectLike } from 'zrender/src/core/BoundingRect';
 import type Model from '../../model/Model';
+import { isCoordinateSystemType } from '../../coord/CoordinateSystem';
 
 const BAR_BORDER_WIDTH_QUERY = ['itemStyle', 'borderWidth'] as const;
 const _eventPos = [0, 0];
@@ -53,12 +54,9 @@ type RectLayout = RectShape;
 
 type BarPossiblePath = Sector | Rect | Sausage
 
-function isCartesian2D(coord: CoordSysOfBar): coord is Cartesian2D {
-    return coord.type === 'cartesian2d';
-}
 
 function getClipArea(coord: CoordSysOfBar, data: List) {
-    if (isCartesian2D(coord)) {
+    if (isCoordinateSystemType<Cartesian2D>(coord, 'cartesian2d')) {
         var coordSysClipArea = coord.getArea && coord.getArea();
         var baseAxis = coord.getBaseAxis();
         // When boundaryGap is false or using time axis. bar may exceed the grid.
@@ -744,7 +742,7 @@ function createBackgroundShape(
     layout: SectorLayout | RectLayout,
     coord: CoordSysOfBar
 ): SectorShape | RectShape {
-    if (isCartesian2D(coord)) {
+    if (isCoordinateSystemType<Cartesian2D>(coord, 'cartesian2d')) {
         const rectShape = layout as RectShape;
         const coordLayout = coord.getArea();
         return {
diff --git a/src/chart/heatmap/HeatmapView.ts b/src/chart/heatmap/HeatmapView.ts
index 52ae3aa..587fd4e 100644
--- a/src/chart/heatmap/HeatmapView.ts
+++ b/src/chart/heatmap/HeatmapView.ts
@@ -28,9 +28,9 @@ import type ExtensionAPI from '../../ExtensionAPI';
 import type VisualMapModel from '../../component/visualMap/VisualMapModel';
 import type PiecewiseModel from '../../component/visualMap/PiecewiseModel';
 import type ContinuousModel from '../../component/visualMap/ContinuousModel';
-import type Cartesian2D from '../../coord/cartesian/Cartesian2D';
-import { CoordinateSystem } from '../../coord/CoordinateSystem';
+import { CoordinateSystem, isCoordinateSystemType } from '../../coord/CoordinateSystem';
 import { StageHandlerProgressParams, Dictionary, OptionDataValue } from '../../util/types';
+import Cartesian2D from '../../coord/cartesian/Cartesian2D';
 
 // Coord can be 'geo' 'bmap' 'amap' 'leaflet'...
 interface GeoLikeCoordSys extends CoordinateSystem {
@@ -38,10 +38,6 @@ interface GeoLikeCoordSys extends CoordinateSystem {
     getViewRect(): graphic.BoundingRect
 }
 
-function isCartesian2D(coord: CoordinateSystem): coord is Cartesian2D {
-    return coord.type === 'cartesian2d';
-}
-
 function getIsInPiecewiseRange(
     dataExtent: number[],
     pieceList: ReturnType<PiecewiseModel['getPieceList']>,
@@ -166,7 +162,7 @@ class HeatmapView extends ChartView {
         var width;
         var height;
 
-        if (isCartesian2D(coordSys)) {
+        if (isCoordinateSystemType<Cartesian2D>(coordSys, 'cartesian2d')) {
             var xAxis = coordSys.getAxis('x');
             var yAxis = coordSys.getAxis('y');
 
@@ -191,7 +187,7 @@ class HeatmapView extends ChartView {
         var labelModel = seriesModel.getModel('label');
         var hoverLabelModel = seriesModel.getModel(['emphasis', 'label']);
 
-        var dataDims = isCartesian2D(coordSys)
+        var dataDims = isCoordinateSystemType<Cartesian2D>(coordSys, 'cartesian2d')
             ? [
                 data.mapDimension('x'),
                 data.mapDimension('y'),
@@ -205,7 +201,7 @@ class HeatmapView extends ChartView {
         for (var idx = start; idx < end; idx++) {
             var rect;
 
-            if (isCartesian2D(coordSys)) {
+            if (isCoordinateSystemType<Cartesian2D>(coordSys, 'cartesian2d')) {
                 // Ignore empty data
                 if (isNaN(data.get(dataDims[2], idx) as number)) {
                     continue;
diff --git a/src/chart/helper/SymbolDraw.ts b/src/chart/helper/SymbolDraw.ts
index 8547efd..05bcdf3 100644
--- a/src/chart/helper/SymbolDraw.ts
+++ b/src/chart/helper/SymbolDraw.ts
@@ -79,7 +79,7 @@ interface RippleEffectOption {
 }
 
 // TODO Separate series and item?
-export interface SymbolDrawItemModelOption extends SymbolOptionMixin {
+export interface SymbolDrawItemModelOption extends SymbolOptionMixin<object> {
     itemStyle?: ItemStyleOption
     label?: LabelOption
     emphasis?: {
diff --git a/src/chart/lines/LinesSeries.ts b/src/chart/lines/LinesSeries.ts
index 589cc14..2aa62b6 100644
--- a/src/chart/lines/LinesSeries.ts
+++ b/src/chart/lines/LinesSeries.ts
@@ -32,9 +32,9 @@ import {
     SeriesOnPolarOptionMixin,
     SeriesOnCalendarOptionMixin,
     SeriesLargeOptionMixin,
-    LabelOption,
     LineStyleOption,
-    OptionDataValue
+    OptionDataValue,
+    LineLabelOption
 } from '../../util/types';
 import GlobalModel from '../../model/Global';
 import type { LineDrawModelOption } from '../helper/LineDraw';
@@ -95,11 +95,11 @@ export interface LinesDataItemOption {
     value?: LinesValue
 
     lineStyle?: LinesLineStyleOption
-    label?: LabelOption
+    label?: LineLabelOption
 
     emphasis?: {
         lineStyle?: LineStyleOption
-        label?: LabelOption
+        label?: LineLabelOption
     }
 }
 
@@ -128,11 +128,11 @@ export interface LinesSeriesOption extends SeriesOption,
      */
     clip?: boolean
 
-    label?: LabelOption
+    label?: LineLabelOption
     lineStyle?: LinesLineStyleOption
 
     emphasis?: {
-        label?: LabelOption
+        label?: LineLabelOption
         lineStyle?: LineStyleOption
     }
 
diff --git a/src/component/axis/axisSplitHelper.ts b/src/component/axis/axisSplitHelper.ts
index 00ad642..29d4b9b 100644
--- a/src/component/axis/axisSplitHelper.ts
+++ b/src/component/axis/axisSplitHelper.ts
@@ -25,11 +25,12 @@ import type SingleAxisView from './SingleAxisView';
 import type CartesianAxisView from './CartesianAxisView';
 import type SingleAxisModel from '../../coord/single/AxisModel';
 import type CartesianAxisModel from '../../coord/cartesian/AxisModel';
+import AxisView from './AxisView';
 
 const inner = makeInner<{
     // Hash map of color index
     splitAreaColors: zrUtil.HashMap<number>
-}>();
+}, AxisView>();
 
 export function rectCoordAxisBuildSplitArea(
     axisView: SingleAxisView | CartesianAxisView,
diff --git a/src/component/axisPointer/BaseAxisPointer.ts b/src/component/axisPointer/BaseAxisPointer.ts
index f6b3316..e9582cd 100644
--- a/src/component/axisPointer/BaseAxisPointer.ts
+++ b/src/component/axisPointer/BaseAxisPointer.ts
@@ -38,7 +38,7 @@ var inner = makeInner<{
     lastProp?: DisplayableProps
     labelEl?: graphic.Rect
     pointerEl?: Displayable
-}>();
+}, Element>();
 var clone = zrUtil.clone;
 var bind = zrUtil.bind;
 
diff --git a/src/component/axisPointer/axisTrigger.ts b/src/component/axisPointer/axisTrigger.ts
index c206479..d5e7c8c 100644
--- a/src/component/axisPointer/axisTrigger.ts
+++ b/src/component/axisPointer/axisTrigger.ts
@@ -25,10 +25,11 @@ import ExtensionAPI from '../../ExtensionAPI';
 import { Dictionary, Payload, CommonAxisPointerOption } from '../../util/types';
 import AxisPointerModel, { AxisPointerOption } from './AxisPointerModel';
 import { each, curry, bind, extend, Curry1 } from 'zrender/src/core/util';
+import { ZRenderType } from 'zrender/src/zrender';
 
 var inner = makeInner<{
     axisPointerLastHighlights: Dictionary<BatchItem>
-}>();
+}, ZRenderType>();
 
 type AxisValue = CommonAxisPointerOption['value'];
 
diff --git a/src/component/axisPointer/globalListener.ts b/src/component/axisPointer/globalListener.ts
index 84b85f7..ca665d8 100644
--- a/src/component/axisPointer/globalListener.ts
+++ b/src/component/axisPointer/globalListener.ts
@@ -56,7 +56,7 @@ interface Pendings {
     hideTip: HideTipPayload[]
 }
 
-const inner = makeInner<InnerStore>();
+const inner = makeInner<InnerStore, ZRenderType>();
 const each = zrUtil.each;
 
 /**
diff --git a/src/component/dataZoom/DataZoomModel.ts b/src/component/dataZoom/DataZoomModel.ts
index d538d89..4760f3a 100644
--- a/src/component/dataZoom/DataZoomModel.ts
+++ b/src/component/dataZoom/DataZoomModel.ts
@@ -669,6 +669,4 @@ function retrieveRawOption<T extends DataZoomOption>(option: T) {
     return ret;
 }
 
-ComponentModel.registerClass(DataZoomModel);
-
 export default DataZoomModel;
\ No newline at end of file
diff --git a/src/component/dataZoom/history.ts b/src/component/dataZoom/history.ts
index ed2ee5a..6ab1efa 100644
--- a/src/component/dataZoom/history.ts
+++ b/src/component/dataZoom/history.ts
@@ -32,7 +32,7 @@ type Store = {
     snapshots: StoreSnapshot[]
 }
 
-const inner = makeInner<Store>();
+const inner = makeInner<Store, GlobalModel>();
 
 /**
  * @param ecModel
diff --git a/src/component/dataZoom/roams.ts b/src/component/dataZoom/roams.ts
index 7d5e836..d0a86b6 100644
--- a/src/component/dataZoom/roams.ts
+++ b/src/component/dataZoom/roams.ts
@@ -61,7 +61,7 @@ interface PayloadBatch {
 
 type Store = Dictionary<Record>
 
-const inner = makeInner<Store>();
+const inner = makeInner<Store, ExtensionAPI>();
 
 export function register(api: ExtensionAPI, dataZoomInfo: DataZoomInfo) {
     var store = inner(api);
diff --git a/src/component/marker/MarkAreaModel.ts b/src/component/marker/MarkAreaModel.ts
index bb82721..2cb7026 100644
--- a/src/component/marker/MarkAreaModel.ts
+++ b/src/component/marker/MarkAreaModel.ts
@@ -17,15 +17,76 @@
 * under the License.
 */
 
-// @ts-nocheck
+import MarkerModel, { MarkerOption, MarkerStatisticType, MarkerPositionOption } from './MarkerModel';
+import { LabelOption, ItemStyleOption } from '../../util/types';
+import ComponentModel from '../../model/Component';
+import GlobalModel from '../../model/Global';
 
-import MarkerModel from './MarkerModel';
+interface MarkAreaDataItemOptionBase {
+    name?: string
 
-export default MarkerModel.extend({
+    itemStyle?: ItemStyleOption
+    label?: LabelOption
 
-    type: 'markArea',
+    emphasis?: {
+        itemStyle?: ItemStyleOption
+        label?: LabelOption
+    }
+}
+
+// 1D markArea for horizontal or vertical. Similar to markLine
+export interface MarkArea1DDataItemOption extends MarkAreaDataItemOptionBase {
+
+    xAxis?: number
+    yAxis?: number
+
+    type?: MarkerStatisticType
+
+    valueIndex?: number
+    valueDim?: string
+}
+
+// 2D markArea on any direction. Similar to markLine
+interface MarkArea2DDataItemDimOption extends MarkAreaDataItemOptionBase, MarkerPositionOption {
+}
+
+
+export type MarkArea2DDataItemOption = [
+    // Start point
+    MarkArea2DDataItemDimOption,
+    // End point
+    MarkArea2DDataItemDimOption
+]
+
+export interface MarkAreaOption extends MarkerOption {
+
+    precision?: number
 
-    defaultOption: {
+    itemStyle?: ItemStyleOption
+    label?: LabelOption
+
+    emphasis?: {
+        itemStyle?: ItemStyleOption
+        label?: LabelOption
+    }
+
+    data?: (MarkArea1DDataItemOption | MarkArea2DDataItemOption)[]
+}
+
+class MarkAreaModel extends MarkerModel<MarkAreaOption> {
+
+    static type = 'markArea'
+    type = MarkAreaModel.type
+
+    createMarkerModelFromSeries(
+        markerOpt: MarkAreaOption,
+        masterMarkerModel: MarkAreaModel,
+        ecModel: GlobalModel
+    ) {
+        return new MarkAreaModel(markerOpt, masterMarkerModel, ecModel);
+    }
+
+    static defaultOption: MarkAreaOption = {
         zlevel: 0,
         // PENDING
         z: 1,
@@ -52,4 +113,8 @@ export default MarkerModel.extend({
             }
         }
     }
-});
\ No newline at end of file
+}
+
+ComponentModel.registerClass(MarkAreaModel);
+
+export default MarkAreaModel;
\ No newline at end of file
diff --git a/src/component/marker/MarkAreaView.ts b/src/component/marker/MarkAreaView.ts
index fc32041..1812ee9 100644
--- a/src/component/marker/MarkAreaView.ts
+++ b/src/component/marker/MarkAreaView.ts
@@ -17,23 +17,52 @@
 * under the License.
 */
 
-// @ts-nocheck
+// TODO Optimize on polar
 
-// TODO Better on polar
-
-import * as zrUtil from 'zrender/src/core/util';
 import * as colorUtil from 'zrender/src/tool/color';
 import List from '../../data/List';
 import * as numberUtil from '../../util/number';
 import * as graphic from '../../util/graphic';
 import * as markerHelper from './markerHelper';
 import MarkerView from './MarkerView';
+import { retrieve, mergeAll, map, defaults, curry, filter, HashMap } from 'zrender/src/core/util';
+import { ScaleDataValue, ParsedValue } from '../../util/types';
+import { CoordinateSystem, isCoordinateSystemType } from '../../coord/CoordinateSystem';
+import MarkAreaModel, { MarkArea2DDataItemOption } from './MarkAreaModel';
+import SeriesModel from '../../model/Series';
+import Cartesian2D from '../../coord/cartesian/Cartesian2D';
+import DataDimensionInfo from '../../data/DataDimensionInfo';
+import ComponentView from '../../view/Component';
+import GlobalModel from '../../model/Global';
+import ExtensionAPI from '../../ExtensionAPI';
+import MarkerModel from './MarkerModel';
+import { makeInner } from '../../util/model';
+
+interface MarkAreaDrawGroup {
+    group: graphic.Group
+}
 
+const inner = makeInner<{
+    data: List<MarkAreaModel>
+}, MarkAreaDrawGroup>();
+
+// Merge two ends option into one.
+type MarkAreaMergedItemOption = Omit<MarkArea2DDataItemOption[number], 'coord'> & {
+    coord: MarkArea2DDataItemOption[number]['coord'][]
+    x0: number | string
+    y0: number | string
+    x1: number | string
+    y1: number | string
+}
 
-var markAreaTransform = function (seriesModel, coordSys, maModel, item) {
+var markAreaTransform = function (
+    seriesModel: SeriesModel,
+    coordSys: CoordinateSystem,
+    maModel: MarkAreaModel,
+    item: MarkArea2DDataItemOption
+): MarkAreaMergedItemOption {
     var lt = markerHelper.dataTransform(seriesModel, item[0]);
     var rb = markerHelper.dataTransform(seriesModel, item[1]);
-    var retrieve = zrUtil.retrieve;
 
     // FIXME make sure lt is less than rb
     var ltCoord = lt.coord;
@@ -45,7 +74,7 @@ var markAreaTransform = function (seriesModel, coordSys, maModel, item) {
     rbCoord[1] = retrieve(rbCoord[1], Infinity);
 
     // Merge option into one
-    var result = zrUtil.mergeAll([{}, lt, rb]);
+    var result: MarkAreaMergedItemOption = mergeAll([{}, lt, rb]);
 
     result.coord = [
         lt.coord, rb.coord
@@ -57,20 +86,25 @@ var markAreaTransform = function (seriesModel, coordSys, maModel, item) {
     return result;
 };
 
-function isInifinity(val) {
-    return !isNaN(val) && !isFinite(val);
+function isInifinity(val: ScaleDataValue) {
+    return !isNaN(val as number) && !isFinite(val as number);
 }
 
 // If a markArea has one dim
-function ifMarkLineHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) {
+function ifMarkAreaHasOnlyDim(
+    dimIndex: number,
+    fromCoord: ScaleDataValue[],
+    toCoord: ScaleDataValue[],
+    coordSys: CoordinateSystem
+) {
     var otherDimIndex = 1 - dimIndex;
     return isInifinity(fromCoord[otherDimIndex]) && isInifinity(toCoord[otherDimIndex]);
 }
 
-function markAreaFilter(coordSys, item) {
+function markAreaFilter(coordSys: CoordinateSystem, item: MarkAreaMergedItemOption) {
     var fromCoord = item.coord[0];
     var toCoord = item.coord[1];
-    if (coordSys.type === 'cartesian2d') {
+    if (isCoordinateSystemType<Cartesian2D>(coordSys, 'cartesian2d')) {
         // In case
         // {
         //  markArea: {
@@ -79,8 +113,8 @@ function markAreaFilter(coordSys, item) {
         // }
         if (
             fromCoord && toCoord
-            && (ifMarkLineHasOnlyDim(1, fromCoord, toCoord, coordSys)
-            || ifMarkLineHasOnlyDim(0, fromCoord, toCoord, coordSys))
+            && (ifMarkAreaHasOnlyDim(1, fromCoord, toCoord, coordSys)
+            || ifMarkAreaHasOnlyDim(0, fromCoord, toCoord, coordSys))
         ) {
             return true;
         }
@@ -98,9 +132,15 @@ function markAreaFilter(coordSys, item) {
 }
 
 // dims can be ['x0', 'y0'], ['x1', 'y1'], ['x0', 'y1'], ['x1', 'y0']
-function getSingleMarkerEndPoint(data, idx, dims, seriesModel, api) {
+function getSingleMarkerEndPoint(
+    data: List<MarkAreaModel>,
+    idx: number,
+    dims: typeof dimPermutations[number],
+    seriesModel: SeriesModel,
+    api: ExtensionAPI
+) {
     var coordSys = seriesModel.coordinateSystem;
-    var itemModel = data.getItemModel(idx);
+    var itemModel = data.getItemModel<MarkAreaMergedItemOption>(idx);
 
     var point;
     var xPx = numberUtil.parsePercent(itemModel.get(dims[0]), api.getWidth());
@@ -117,17 +157,17 @@ function getSingleMarkerEndPoint(data, idx, dims, seriesModel, api) {
             );
         }
         else {
-            var x = data.get(dims[0], idx);
-            var y = data.get(dims[1], idx);
+            var x = data.get(dims[0], idx) as number;
+            var y = data.get(dims[1], idx) as number;
             var pt = [x, y];
             coordSys.clampData && coordSys.clampData(pt, pt);
             point = coordSys.dataToPoint(pt, true);
         }
-        if (coordSys.type === 'cartesian2d') {
+        if (isCoordinateSystemType<Cartesian2D>(coordSys, 'cartesian2d')) {
             var xAxis = coordSys.getAxis('x');
             var yAxis = coordSys.getAxis('y');
-            var x = data.get(dims[0], idx);
-            var y = data.get(dims[1], idx);
+            var x = data.get(dims[0], idx) as number;
+            var y = data.get(dims[1], idx) as number;
             if (isInifinity(x)) {
                 point[0] = xAxis.toGlobalCoord(xAxis.getExtent()[dims[0] === 'x0' ? 0 : 1]);
             }
@@ -148,49 +188,39 @@ function getSingleMarkerEndPoint(data, idx, dims, seriesModel, api) {
     return point;
 }
 
-var dimPermutations = [['x0', 'y0'], ['x1', 'y0'], ['x1', 'y1'], ['x0', 'y1']];
-
-MarkerView.extend({
-
-    type: 'markArea',
-
-    // updateLayout: function (markAreaModel, ecModel, api) {
-    //     ecModel.eachSeries(function (seriesModel) {
-    //         var maModel = seriesModel.markAreaModel;
-    //         if (maModel) {
-    //             var areaData = maModel.getData();
-    //             areaData.each(function (idx) {
-    //                 var points = zrUtil.map(dimPermutations, function (dim) {
-    //                     return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);
-    //                 });
-    //                 // Layout
-    //                 areaData.setItemLayout(idx, points);
-    //                 var el = areaData.getItemGraphicEl(idx);
-    //                 el.setShape('points', points);
-    //             });
-    //         }
-    //     }, this);
-    // },
-
-    updateTransform: function (markAreaModel, ecModel, api) {
+var dimPermutations = [['x0', 'y0'], ['x1', 'y0'], ['x1', 'y1'], ['x0', 'y1']] as const;
+
+class MarkAreaView extends MarkerView {
+
+    static type = 'markArea'
+    type = MarkAreaView.type
+
+    markerGroupMap: HashMap<MarkAreaDrawGroup>
+
+    updateTransform(markAreaModel: MarkAreaModel, ecModel: GlobalModel, api: ExtensionAPI) {
         ecModel.eachSeries(function (seriesModel) {
-            var maModel = seriesModel.markAreaModel;
+            var maModel = MarkerModel.getMarkerModelFromSeries(seriesModel, 'markArea');
             if (maModel) {
                 var areaData = maModel.getData();
                 areaData.each(function (idx) {
-                    var points = zrUtil.map(dimPermutations, function (dim) {
+                    var points = map(dimPermutations, function (dim) {
                         return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);
                     });
                     // Layout
                     areaData.setItemLayout(idx, points);
-                    var el = areaData.getItemGraphicEl(idx);
+                    var el = areaData.getItemGraphicEl(idx) as graphic.Rect;
                     el.setShape('points', points);
                 });
             }
         }, this);
-    },
+    }
 
-    renderSeries: function (seriesModel, maModel, ecModel, api) {
+    renderSeries(
+        seriesModel: SeriesModel,
+        maModel: MarkAreaModel,
+        ecModel: GlobalModel,
+        api: ExtensionAPI
+    ) {
         var coordSys = seriesModel.coordinateSystem;
         var seriesId = seriesModel.id;
         var seriesData = seriesModel.getData();
@@ -200,7 +230,7 @@ MarkerView.extend({
             || areaGroupMap.set(seriesId, {group: new graphic.Group()});
 
         this.group.add(polygonGroup.group);
-        polygonGroup.__keep = true;
+        this.markKeep(polygonGroup);
 
         var areaData = createList(coordSys, seriesModel, maModel);
 
@@ -210,7 +240,7 @@ MarkerView.extend({
         // Update visual and layout of line
         areaData.each(function (idx) {
             // Layout
-            areaData.setItemLayout(idx, zrUtil.map(dimPermutations, function (dim) {
+            areaData.setItemLayout(idx, map(dimPermutations, function (dim) {
                 return getSingleMarkerEndPoint(areaData, idx, dim, seriesModel, api);
             }));
 
@@ -221,7 +251,7 @@ MarkerView.extend({
         });
 
 
-        areaData.diff(polygonGroup.__data)
+        areaData.diff(inner(polygonGroup).data)
             .add(function (idx) {
                 var polygon = new graphic.Polygon({
                     shape: {
@@ -232,7 +262,7 @@ MarkerView.extend({
                 polygonGroup.group.add(polygon);
             })
             .update(function (newIdx, oldIdx) {
-                var polygon = polygonGroup.__data.getItemGraphicEl(oldIdx);
+                var polygon = inner(polygonGroup).data.getItemGraphicEl(oldIdx) as graphic.Polygon;
                 graphic.updateProps(polygon, {
                     shape: {
                         points: areaData.getItemLayout(newIdx)
@@ -242,18 +272,18 @@ MarkerView.extend({
                 areaData.setItemGraphicEl(newIdx, polygon);
             })
             .remove(function (idx) {
-                var polygon = polygonGroup.__data.getItemGraphicEl(idx);
+                var polygon = inner(polygonGroup).data.getItemGraphicEl(idx);
                 polygonGroup.group.remove(polygon);
             })
             .execute();
 
-        areaData.eachItemGraphicEl(function (polygon, idx) {
-            var itemModel = areaData.getItemModel(idx);
+        areaData.eachItemGraphicEl(function (polygon: graphic.Polygon, idx) {
+            var itemModel = areaData.getItemModel<MarkAreaMergedItemOption>(idx);
             var labelModel = itemModel.getModel('label');
-            var labelHoverModel = itemModel.getModel('emphasis.label');
+            var labelHoverModel = itemModel.getModel(['emphasis', 'label']);
             var color = areaData.getItemVisual(idx, 'color');
             polygon.useStyle(
-                zrUtil.defaults(
+                defaults(
                     itemModel.getModel('itemStyle').getItemStyle(),
                     {
                         fill: colorUtil.modifyAlpha(color, 0.4),
@@ -262,7 +292,7 @@ MarkerView.extend({
                 )
             );
 
-            polygon.hoverStyle = itemModel.getModel('emphasis.itemStyle').getItemStyle();
+            polygon.hoverStyle = itemModel.getModel(['emphasis', 'itemStyle']).getItemStyle();
 
             graphic.setLabelStyle(
                 polygon.style, polygon.hoverStyle, labelModel, labelHoverModel,
@@ -277,36 +307,36 @@ MarkerView.extend({
 
             graphic.setHoverStyle(polygon, {});
 
-            polygon.dataModel = maModel;
+            graphic.getECData(polygon).dataModel = maModel;
         });
 
-        polygonGroup.__data = areaData;
+        inner(polygonGroup).data = areaData;
 
         polygonGroup.group.silent = maModel.get('silent') || seriesModel.get('silent');
     }
-});
-
-/**
- * @inner
- * @param {module:echarts/coord/*} coordSys
- * @param {module:echarts/model/Series} seriesModel
- * @param {module:echarts/model/Model} mpModel
- */
-function createList(coordSys, seriesModel, maModel) {
-
-    var coordDimsInfos;
-    var areaData;
+}
+
+function createList(
+    coordSys: CoordinateSystem,
+    seriesModel: SeriesModel,
+    maModel: MarkAreaModel
+) {
+
+    var coordDimsInfos: DataDimensionInfo[];
+    var areaData: List<MarkAreaModel>;
     var dims = ['x0', 'y0', 'x1', 'y1'];
     if (coordSys) {
-        coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) {
+        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {
             var data = seriesModel.getData();
             var info = data.getDimensionInfo(
                 data.mapDimension(coordDim)
             ) || {};
             // In map series data don't have lng and lat dimension. Fallback to same with coordSys
-            return zrUtil.defaults({name: coordDim}, info);
+            return defaults({
+                name: coordDim
+            }, info);
         });
-        areaData = new List(zrUtil.map(dims, function (dim, idx) {
+        areaData = new List(map(dims, function (dim, idx) {
             return {
                 name: dim,
                 type: coordDimsInfos[idx % 2].type
@@ -321,21 +351,29 @@ function createList(coordSys, seriesModel, maModel) {
         areaData = new List(coordDimsInfos, maModel);
     }
 
-    var optData = zrUtil.map(maModel.get('data'), zrUtil.curry(
+    var optData = map(maModel.get('data'), curry(
         markAreaTransform, seriesModel, coordSys, maModel
     ));
     if (coordSys) {
-        optData = zrUtil.filter(
-            optData, zrUtil.curry(markAreaFilter, coordSys)
+        optData = filter(
+            optData, curry(markAreaFilter, coordSys)
         );
     }
 
-    var dimValueGetter = coordSys ? function (item, dimName, dataIndex, dimIndex) {
-        return item.coord[Math.floor(dimIndex / 2)][dimIndex % 2];
-    } : function (item) {
+    var dimValueGetter = coordSys ? function (
+        item: MarkAreaMergedItemOption,
+        dimName: string,
+        dataIndex: number,
+        dimIndex: number
+    ) {
+        // TODO should convert to ParsedValue?
+        return item.coord[Math.floor(dimIndex / 2)][dimIndex % 2] as ParsedValue;
+    } : function (item: MarkAreaMergedItemOption) {
         return item.value;
     };
     areaData.initData(optData, null, dimValueGetter);
     areaData.hasItemOption = true;
     return areaData;
-}
\ No newline at end of file
+}
+
+ComponentView.registerClass(MarkAreaView);
\ No newline at end of file
diff --git a/src/component/marker/MarkLineModel.ts b/src/component/marker/MarkLineModel.ts
index 10d6aac..ca41492 100644
--- a/src/component/marker/MarkLineModel.ts
+++ b/src/component/marker/MarkLineModel.ts
@@ -17,15 +17,105 @@
 * under the License.
 */
 
-// @ts-nocheck
+import MarkerModel, { MarkerOption, MarkerStatisticType, MarkerPositionOption } from './MarkerModel';
+import ComponentModel from '../../model/Component';
+import GlobalModel from '../../model/Global';
+import { LineStyleOption, LineLabelOption, SymbolOptionMixin, ItemStyleOption } from '../../util/types';
 
-import MarkerModel from './MarkerModel';
+interface MarkLineDataItemOptionBase {
+    name?: string
 
-export default MarkerModel.extend({
+    lineStyle?: LineStyleOption
+    /**
+     * itemStyle for symbol
+     */
+    itemStyle?: ItemStyleOption
+    label?: LineLabelOption
 
-    type: 'markLine',
+    emphasis?: {
+        itemStyle?: ItemStyleOption
+        lineStyle?: LineStyleOption
+        label?: LineLabelOption
+    }
+}
+
+// 1D markLine for horizontal or vertical
+export interface MarkLine1DDataItemOption extends MarkLineDataItemOptionBase {
+
+    // On cartesian coordinate system
+    xAxis?: number
+    yAxis?: number
+
+    // Use statistic method
+    type?: MarkerStatisticType
+    /**
+     * When using statistic method with type.
+     * valueIndex and valueDim can be specify which dim the statistic is used on.
+     */
+    valueIndex?: number
+    valueDim?: string
+
+    /**
+     * Symbol for both two ends
+     */
+    symbol?: string[] | string
+    symbolSize?: number[] | number
+}
+
+// 2D markLine on any direction
+interface MarkLine2DDataItemDimOption extends
+    MarkLineDataItemOptionBase,
+    SymbolOptionMixin,
+    MarkerPositionOption {
+}
+
+export type MarkLine2DDataItemOption = [
+    // Start point
+    MarkLine2DDataItemDimOption,
+    // End point
+    MarkLine2DDataItemDimOption
+]
+
+export interface MarkLineOption extends MarkerOption {
+
+    symbol?: string[] | string
+    symbolSize?: number[] | number
+
+    /**
+     * Precision used on statistic method
+     */
+    precision?: number
 
-    defaultOption: {
+    /**
+     * itemStyle for symbol.
+     */
+    itemStyle?: ItemStyleOption
+    lineStyle?: LineStyleOption
+    label?: LineLabelOption
+
+    emphasis?: {
+        itemStyle?: ItemStyleOption
+        lineStyle?: LineStyleOption
+        label?: LineLabelOption
+    }
+
+    data?: (MarkLine1DDataItemOption | MarkLine2DDataItemOption)[]
+}
+
+class MarkLineModel extends MarkerModel<MarkLineOption> {
+
+    static type = 'markLine'
+    type = MarkLineModel.type
+
+    createMarkerModelFromSeries(
+        markerOpt: MarkLineOption,
+        masterMarkerModel: MarkLineModel,
+        ecModel: GlobalModel
+    ) {
+        return new MarkLineModel(markerOpt, masterMarkerModel, ecModel);
+    }
+
+    static defaultOption: MarkLineOption = {
         zlevel: 0,
         z: 5,
 
@@ -56,4 +146,8 @@ export default MarkerModel.extend({
         },
         animationEasing: 'linear'
     }
-});
\ No newline at end of file
+}
+
+ComponentModel.registerClass(MarkLineModel);
+
+export default MarkLineModel;
\ No newline at end of file
diff --git a/src/component/marker/MarkLineView.ts b/src/component/marker/MarkLineView.ts
index 7f9f78b..2324f0c 100644
--- a/src/component/marker/MarkLineView.ts
+++ b/src/component/marker/MarkLineView.ts
@@ -17,101 +17,161 @@
 * under the License.
 */
 
-// @ts-nocheck
-
-import * as zrUtil from 'zrender/src/core/util';
 import List from '../../data/List';
 import * as numberUtil from '../../util/number';
 import * as markerHelper from './markerHelper';
 import LineDraw from '../../chart/helper/LineDraw';
 import MarkerView from './MarkerView';
 import {getStackedDimension} from '../../data/helper/dataStackHelper';
-
-var markLineTransform = function (seriesModel, coordSys, mlModel, item) {
+import { CoordinateSystem, isCoordinateSystemType } from '../../coord/CoordinateSystem';
+import MarkLineModel, { MarkLine2DDataItemOption, MarkLineOption } from './MarkLineModel';
+import { ScaleDataValue } from '../../util/types';
+import SeriesModel from '../../model/Series';
+import { __DEV__ } from '../../config';
+import { getECData } from '../../util/graphic';
+import ExtensionAPI from '../../ExtensionAPI';
+import Cartesian2D from '../../coord/cartesian/Cartesian2D';
+import GlobalModel from '../../model/Global';
+import MarkerModel from './MarkerModel';
+import {
+    isArray,
+    retrieve,
+    clone,
+    extend,
+    logError,
+    merge,
+    map,
+    defaults,
+    curry,
+    filter,
+    HashMap
+} from 'zrender/src/core/util';
+import ComponentView from '../../view/Component';
+import { makeInner } from '../../util/model';
+
+// Item option for configuring line and each end of symbol.
+// Line option. be merged from configuration of two ends.
+type MarkLineMergedItemOption = MarkLine2DDataItemOption[number]
+
+const inner = makeInner<{
+    // from data
+    from: List<MarkLineModel>
+    // to data
+    to: List<MarkLineModel>
+}, MarkLineModel>();
+
+var markLineTransform = function (
+    seriesModel: SeriesModel,
+    coordSys: CoordinateSystem,
+    mlModel: MarkLineModel,
+    item: MarkLineOption['data'][number]
+) {
     var data = seriesModel.getData();
-    // Special type markLine like 'min', 'max', 'average', 'median'
-    var mlType = item.type;
 
-    if (!zrUtil.isArray(item)
-        && (
+    let itemArray: MarkLineMergedItemOption[];
+    if (!isArray(item)) {
+        // Special type markLine like 'min', 'max', 'average', 'median'
+        var mlType = item.type;
+        if (
             mlType === 'min' || mlType === 'max' || mlType === 'average' || mlType === 'median'
             // In case
             // data: [{
             //   yAxis: 10
             // }]
             || (item.xAxis != null || item.yAxis != null)
-        )
-    ) {
-        var valueAxis;
-        var value;
+        ) {
 
-        if (item.yAxis != null || item.xAxis != null) {
-            valueAxis = coordSys.getAxis(item.yAxis != null ? 'y' : 'x');
-            value = zrUtil.retrieve(item.yAxis, item.xAxis);
-        }
-        else {
-            var axisInfo = markerHelper.getAxisInfo(item, data, coordSys, seriesModel);
-            valueAxis = axisInfo.valueAxis;
-            var valueDataDim = getStackedDimension(data, axisInfo.valueDataDim);
-            value = markerHelper.numCalculate(data, valueDataDim, mlType);
-        }
-        var valueIndex = valueAxis.dim === 'x' ? 0 : 1;
-        var baseIndex = 1 - valueIndex;
+            var valueAxis;
+            var value;
 
-        var mlFrom = zrUtil.clone(item);
-        var mlTo = {};
+            if (item.yAxis != null || item.xAxis != null) {
+                valueAxis = coordSys.getAxis(item.yAxis != null ? 'y' : 'x');
+                value = retrieve(item.yAxis, item.xAxis);
+            }
+            else {
+                var axisInfo = markerHelper.getAxisInfo(item, data, coordSys, seriesModel);
+                valueAxis = axisInfo.valueAxis;
+                var valueDataDim = getStackedDimension(data, axisInfo.valueDataDim);
+                value = markerHelper.numCalculate(data, valueDataDim, mlType);
+            }
+            var valueIndex = valueAxis.dim === 'x' ? 0 : 1;
+            var baseIndex = 1 - valueIndex;
 
-        mlFrom.type = null;
+            // Normized to 2d data with start and end point
+            var mlFrom = clone(item) as MarkLine2DDataItemOption[number];
+            var mlTo = {
+                coord: []
+            } as MarkLine2DDataItemOption[number];
 
-        mlFrom.coord = [];
-        mlTo.coord = [];
-        mlFrom.coord[baseIndex] = -Infinity;
-        mlTo.coord[baseIndex] = Infinity;
+            mlFrom.type = null;
 
-        var precision = mlModel.get('precision');
-        if (precision >= 0 && typeof value === 'number') {
-            value = +value.toFixed(Math.min(precision, 20));
-        }
+            mlFrom.coord = [];
+            mlFrom.coord[baseIndex] = -Infinity;
+            mlTo.coord[baseIndex] = Infinity;
 
-        mlFrom.coord[valueIndex] = mlTo.coord[valueIndex] = value;
+            var precision = mlModel.get('precision');
+            if (precision >= 0 && typeof value === 'number') {
+                value = +value.toFixed(Math.min(precision, 20));
+            }
 
-        item = [mlFrom, mlTo, { // Extra option for tooltip and label
-            type: mlType,
-            valueIndex: item.valueIndex,
-            // Force to use the value of calculated value.
-            value: value
-        }];
+            mlFrom.coord[valueIndex] = mlTo.coord[valueIndex] = value;
+
+            itemArray = [mlFrom, mlTo, { // Extra option for tooltip and label
+                type: mlType,
+                valueIndex: item.valueIndex,
+                // Force to use the value of calculated value.
+                value: value
+            }];
+        }
+        else {
+            // Invalid data
+            if (__DEV__) {
+                logError('Invalid markLine data.');
+            }
+            itemArray = [];
+        }
+    }
+    else {
+        itemArray = item;
     }
 
-    item = [
-        markerHelper.dataTransform(seriesModel, item[0]),
-        markerHelper.dataTransform(seriesModel, item[1]),
-        zrUtil.extend({}, item[2])
+    const normalizedItem = [
+        markerHelper.dataTransform(seriesModel, itemArray[0]),
+        markerHelper.dataTransform(seriesModel, itemArray[1]),
+        extend({}, itemArray[2])
     ];
 
     // Avoid line data type is extended by from(to) data type
-    item[2].type = item[2].type || '';
+    normalizedItem[2].type = normalizedItem[2].type || null;
 
     // Merge from option and to option into line option
-    zrUtil.merge(item[2], item[0]);
-    zrUtil.merge(item[2], item[1]);
+    merge(normalizedItem[2], normalizedItem[0]);
+    merge(normalizedItem[2], normalizedItem[1]);
 
-    return item;
+    return normalizedItem;
 };
 
-function isInifinity(val) {
-    return !isNaN(val) && !isFinite(val);
+function isInifinity(val: ScaleDataValue) {
+    return !isNaN(val as number) && !isFinite(val as number);
 }
 
 // If a markLine has one dim
-function ifMarkLineHasOnlyDim(dimIndex, fromCoord, toCoord, coordSys) {
+function ifMarkLineHasOnlyDim(
+    dimIndex: number,
+    fromCoord: ScaleDataValue[],
+    toCoord: ScaleDataValue[],
+    coordSys: CoordinateSystem
+) {
     var otherDimIndex = 1 - dimIndex;
     var dimName = coordSys.dimensions[dimIndex];
     return isInifinity(fromCoord[otherDimIndex]) && isInifinity(toCoord[otherDimIndex])
         && fromCoord[dimIndex] === toCoord[dimIndex] && coordSys.getAxis(dimName).containData(fromCoord[dimIndex]);
 }
 
-function markLineFilter(coordSys, item) {
+function markLineFilter(
+    coordSys: CoordinateSystem,
+    item: MarkLine2DDataItemOption
+) {
     if (coordSys.type === 'cartesian2d') {
         var fromCoord = item[0].coord;
         var toCoord = item[1].coord;
@@ -134,10 +194,14 @@ function markLineFilter(coordSys, item) {
 }
 
 function updateSingleMarkerEndLayout(
-    data, idx, isFrom, seriesModel, api
+    data: List<MarkLineModel>,
+    idx: number,
+    isFrom: boolean,
+    seriesModel: SeriesModel,
+    api: ExtensionAPI
 ) {
     var coordSys = seriesModel.coordinateSystem;
-    var itemModel = data.getItemModel(idx);
+    var itemModel = data.getItemModel<MarkLine2DDataItemOption[number]>(idx);
 
     var point;
     var xPx = numberUtil.parsePercent(itemModel.get('x'), api.getWidth());
@@ -168,7 +232,7 @@ function updateSingleMarkerEndLayout(
         //      type: 'average'
         //    }]
         //  }
-        if (coordSys.type === 'cartesian2d') {
+        if (isCoordinateSystemType<Cartesian2D>(coordSys, 'cartesian2d')) {
             var xAxis = coordSys.getAxis('x');
             var yAxis = coordSys.getAxis('y');
             var dims = coordSys.dimensions;
@@ -192,43 +256,20 @@ function updateSingleMarkerEndLayout(
     data.setItemLayout(idx, point);
 }
 
-export default MarkerView.extend({
-
-    type: 'markLine',
-
-    // updateLayout: function (markLineModel, ecModel, api) {
-    //     ecModel.eachSeries(function (seriesModel) {
-    //         var mlModel = seriesModel.markLineModel;
-    //         if (mlModel) {
-    //             var mlData = mlModel.getData();
-    //             var fromData = mlModel.__from;
-    //             var toData = mlModel.__to;
-    //             // Update visual and layout of from symbol and to symbol
-    //             fromData.each(function (idx) {
-    //                 updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api);
-    //                 updateSingleMarkerEndLayout(toData, idx, false, seriesModel, api);
-    //             });
-    //             // Update layout of line
-    //             mlData.each(function (idx) {
-    //                 mlData.setItemLayout(idx, [
-    //                     fromData.getItemLayout(idx),
-    //                     toData.getItemLayout(idx)
-    //                 ]);
-    //             });
-
-    //             this.markerGroupMap.get(seriesModel.id).updateLayout();
-
-    //         }
-    //     }, this);
-    // },
-
-    updateTransform: function (markLineModel, ecModel, api) {
+class MarkLineView extends MarkerView {
+
+    static type = 'markLine'
+    type = MarkLineView.type
+
+    markerGroupMap: HashMap<LineDraw>
+
+    updateTransform(markLineModel: MarkLineModel, ecModel: GlobalModel, api: ExtensionAPI) {
         ecModel.eachSeries(function (seriesModel) {
-            var mlModel = seriesModel.markLineModel;
+            var mlModel = MarkerModel.getMarkerModelFromSeries(seriesModel, 'markLine') as MarkLineModel;
             if (mlModel) {
                 var mlData = mlModel.getData();
-                var fromData = mlModel.__from;
-                var toData = mlModel.__to;
+                var fromData = inner(mlModel).from;
+                var toData = inner(mlModel).to;
                 // Update visual and layout of from symbol and to symbol
                 fromData.each(function (idx) {
                     updateSingleMarkerEndLayout(fromData, idx, true, seriesModel, api);
@@ -246,9 +287,14 @@ export default MarkerView.extend({
 
             }
         }, this);
-    },
+    }
 
-    renderSeries: function (seriesModel, mlModel, ecModel, api) {
+    renderSeries(
+        seriesModel: SeriesModel,
+        mlModel: MarkLineModel,
+        ecModel: GlobalModel,
+        api: ExtensionAPI
+    ) {
         var coordSys = seriesModel.coordinateSystem;
         var seriesId = seriesModel.id;
         var seriesData = seriesModel.getData();
@@ -264,17 +310,17 @@ export default MarkerView.extend({
         var toData = mlData.to;
         var lineData = mlData.line;
 
-        mlModel.__from = fromData;
-        mlModel.__to = toData;
+        inner(mlModel).from = fromData;
+        inner(mlModel).to = toData;
         // Line data for tooltip and formatter
         mlModel.setData(lineData);
 
         var symbolType = mlModel.get('symbol');
         var symbolSize = mlModel.get('symbolSize');
-        if (!zrUtil.isArray(symbolType)) {
+        if (!isArray(symbolType)) {
             symbolType = [symbolType, symbolType];
         }
-        if (typeof symbolSize === 'number') {
+        if (!isArray(symbolSize)) {
             symbolSize = [symbolSize, symbolSize];
         }
 
@@ -286,7 +332,7 @@ export default MarkerView.extend({
 
         // Update visual and layout of line
         lineData.each(function (idx) {
-            var lineColor = lineData.getItemModel(idx).get('lineStyle.color');
+            var lineColor = lineData.getItemModel<MarkLineMergedItemOption>(idx).get(['lineStyle', 'color']);
             lineData.setItemVisual(idx, {
                 color: lineColor || fromData.getItemVisual(idx, 'color')
             });
@@ -309,46 +355,44 @@ export default MarkerView.extend({
         // FIXME
         mlData.line.eachItemGraphicEl(function (el, idx) {
             el.traverse(function (child) {
-                child.dataModel = mlModel;
+                getECData(child).dataModel = mlModel;
             });
         });
 
-        function updateDataVisualAndLayout(data, idx, isFrom) {
-            var itemModel = data.getItemModel(idx);
+        function updateDataVisualAndLayout(
+            data: List<MarkLineModel>,
+            idx: number,
+            isFrom: boolean
+        ) {
+            var itemModel = data.getItemModel<MarkLineMergedItemOption>(idx);
 
             updateSingleMarkerEndLayout(
                 data, idx, isFrom, seriesModel, api
             );
 
             data.setItemVisual(idx, {
-                symbolSize: itemModel.get('symbolSize') || symbolSize[isFrom ? 0 : 1],
-                symbol: itemModel.get('symbol', true) || symbolType[isFrom ? 0 : 1],
-                color: itemModel.get('itemStyle.color') || seriesData.getVisual('color')
+                symbolSize: itemModel.get('symbolSize') || (symbolSize as number[])[isFrom ? 0 : 1],
+                symbol: itemModel.get('symbol', true) || (symbolType as string[])[isFrom ? 0 : 1],
+                color: itemModel.get(['itemStyle', 'color']) || seriesData.getVisual('color')
             });
         }
 
-        lineDraw.__keep = true;
+        this.markKeep(lineDraw);
 
         lineDraw.group.silent = mlModel.get('silent') || seriesModel.get('silent');
     }
-});
+}
 
-/**
- * @inner
- * @param {module:echarts/coord/*} coordSys
- * @param {module:echarts/model/Series} seriesModel
- * @param {module:echarts/model/Model} mpModel
- */
-function createList(coordSys, seriesModel, mlModel) {
+function createList(coordSys: CoordinateSystem, seriesModel: SeriesModel, mlModel: MarkLineModel) {
 
     var coordDimsInfos;
     if (coordSys) {
-        coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) {
+        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {
             var info = seriesModel.getData().getDimensionInfo(
                 seriesModel.getData().mapDimension(coordDim)
             ) || {};
             // In map series data don't have lng and lat dimension. Fallback to same with coordSys
-            return zrUtil.defaults({name: coordDim}, info);
+            return defaults({name: coordDim}, info);
         });
     }
     else {
@@ -363,33 +407,33 @@ function createList(coordSys, seriesModel, mlModel) {
     // No dimensions
     var lineData = new List([], mlModel);
 
-    var optData = zrUtil.map(mlModel.get('data'), zrUtil.curry(
+    var optData = map(mlModel.get('data'), curry(
         markLineTransform, seriesModel, coordSys, mlModel
     ));
     if (coordSys) {
-        optData = zrUtil.filter(
-            optData, zrUtil.curry(markLineFilter, coordSys)
+        optData = filter(
+            optData, curry(markLineFilter, coordSys)
         );
     }
-    var dimValueGetter = coordSys ? markerHelper.dimValueGetter : function (item) {
+    var dimValueGetter = coordSys ? markerHelper.dimValueGetter : function (item: MarkLineMergedItemOption) {
         return item.value;
     };
     fromData.initData(
-        zrUtil.map(optData, function (item) {
+        map(optData, function (item) {
             return item[0];
         }),
         null,
         dimValueGetter
     );
     toData.initData(
-        zrUtil.map(optData, function (item) {
+        map(optData, function (item) {
             return item[1];
         }),
         null,
         dimValueGetter
     );
     lineData.initData(
-        zrUtil.map(optData, function (item) {
+        map(optData, function (item) {
             return item[2];
         })
     );
@@ -401,3 +445,5 @@ function createList(coordSys, seriesModel, mlModel) {
         line: lineData
     };
 }
+
+ComponentView.registerClass(MarkLineView);
diff --git a/src/component/marker/MarkPointModel.ts b/src/component/marker/MarkPointModel.ts
index 06bb4c1..3d33971 100644
--- a/src/component/marker/MarkPointModel.ts
+++ b/src/component/marker/MarkPointModel.ts
@@ -17,15 +17,63 @@
 * under the License.
 */
 
-// @ts-nocheck
+import MarkerModel, { MarkerOption, MarkerPositionOption } from './MarkerModel';
+import ComponentModel from '../../model/Component';
+import GlobalModel from '../../model/Global';
+import { SymbolOptionMixin, ItemStyleOption, LabelOption, CallbackDataParams } from '../../util/types';
+import List from '../../data/List';
 
-import MarkerModel from './MarkerModel';
+// interface MarkPointCallbackDataParams extends CallbackDataParams {
+//     componentType: 'markPoint'
+//     componentSubType: never
+// }
 
-export default MarkerModel.extend({
+export interface MarkPointDataItemOption extends
+    // TODO should not support callback in data
+    SymbolOptionMixin<CallbackDataParams>,
+    MarkerPositionOption {
+    name: string
 
-    type: 'markPoint',
+    itemStyle?: ItemStyleOption
+    label?: LabelOption
 
-    defaultOption: {
+    emphasis?: {
+        itemStyle?: ItemStyleOption
+        label?: LabelOption
+    }
+
+}
+
+export interface MarkPointOption extends MarkerOption,
+    SymbolOptionMixin<CallbackDataParams> {
+
+    precision?: number
+
+    itemStyle?: ItemStyleOption
+    label?: LabelOption
+
+    emphasis?: {
+        itemStyle?: ItemStyleOption
+        label?: LabelOption
+    }
+
+    data?: MarkPointDataItemOption[]
+}
+
+class MarkPointModel extends MarkerModel<MarkPointOption> {
+
+    static type = 'markPoint'
+    type = MarkPointModel.type
+
+    createMarkerModelFromSeries(
+        markerOpt: MarkPointOption,
+        masterMarkerModel: MarkPointModel,
+        ecModel: GlobalModel
+    ) {
+        return new MarkPointModel(markerOpt, masterMarkerModel, ecModel);
+    }
+
+    static defaultOption: MarkPointOption = {
         zlevel: 0,
         z: 5,
         symbol: 'pin',
@@ -48,4 +96,8 @@ export default MarkerModel.extend({
             }
         }
     }
-});
\ No newline at end of file
+}
+
+ComponentModel.registerClass(MarkPointModel);
+
+export default MarkPointModel;
\ No newline at end of file
diff --git a/src/component/marker/MarkPointView.ts b/src/component/marker/MarkPointView.ts
index 8646f50..cc9e4dd 100644
--- a/src/component/marker/MarkPointView.ts
+++ b/src/component/marker/MarkPointView.ts
@@ -17,19 +17,30 @@
 * under the License.
 */
 
-// @ts-nocheck
 
-import * as zrUtil from 'zrender/src/core/util';
 import SymbolDraw from '../../chart/helper/SymbolDraw';
 import * as numberUtil from '../../util/number';
 import List from '../../data/List';
 import * as markerHelper from './markerHelper';
 import MarkerView from './MarkerView';
-
-function updateMarkerLayout(mpData, seriesModel, api) {
+import ComponentView from '../../view/Component';
+import { CoordinateSystem } from '../../coord/CoordinateSystem';
+import SeriesModel from '../../model/Series';
+import MarkPointModel, {MarkPointDataItemOption} from './MarkPointModel';
+import GlobalModel from '../../model/Global';
+import MarkerModel from './MarkerModel';
+import ExtensionAPI from '../../ExtensionAPI';
+import { HashMap, isFunction, map, defaults, filter, curry } from 'zrender/src/core/util';
+import { getECData } from '../../util/graphic';
+
+function updateMarkerLayout(
+    mpData: List<MarkPointModel>,
+    seriesModel: SeriesModel,
+    api: ExtensionAPI
+) {
     var coordSys = seriesModel.coordinateSystem;
-    mpData.each(function (idx) {
-        var itemModel = mpData.getItemModel(idx);
+    mpData.each(function (idx: number) {
+        var itemModel = mpData.getItemModel<MarkPointDataItemOption>(idx);
         var point;
         var xPx = numberUtil.parsePercent(itemModel.get('x'), api.getWidth());
         var yPx = numberUtil.parsePercent(itemModel.get('y'), api.getHeight());
@@ -62,31 +73,31 @@ function updateMarkerLayout(mpData, seriesModel, api) {
     });
 }
 
-export default MarkerView.extend({
+class MarkPointView extends MarkerView {
 
-    type: 'markPoint',
+    static type = 'markPoint'
 
-    // updateLayout: function (markPointModel, ecModel, api) {
-    //     ecModel.eachSeries(function (seriesModel) {
-    //         var mpModel = seriesModel.markPointModel;
-    //         if (mpModel) {
-    //             updateMarkerLayout(mpModel.getData(), seriesModel, api);
-    //             this.markerGroupMap.get(seriesModel.id).updateLayout(mpModel);
-    //         }
-    //     }, this);
-    // },
+    markerGroupMap: HashMap<SymbolDraw>
 
-    updateTransform: function (markPointModel, ecModel, api) {
+    updateTransform(markPointModel: MarkPointModel, ecModel: GlobalModel, api: ExtensionAPI) {
         ecModel.eachSeries(function (seriesModel) {
-            var mpModel = seriesModel.markPointModel;
+            var mpModel = MarkerModel.getMarkerModelFromSeries(seriesModel, 'markPoint') as MarkPointModel;
             if (mpModel) {
-                updateMarkerLayout(mpModel.getData(), seriesModel, api);
-                this.markerGroupMap.get(seriesModel.id).updateLayout(mpModel);
+                updateMarkerLayout(
+                    mpModel.getData(),
+                    seriesModel, api
+                );
+                this.markerGroupMap.get(seriesModel.id).updateLayout();
             }
         }, this);
-    },
+    }
 
-    renderSeries: function (seriesModel, mpModel, ecModel, api) {
+    renderSeries(
+        seriesModel: SeriesModel,
+        mpModel: MarkPointModel,
+        ecModel: GlobalModel,
+        api: ExtensionAPI
+    ) {
         var coordSys = seriesModel.coordinateSystem;
         var seriesId = seriesModel.id;
         var seriesData = seriesModel.getData();
@@ -103,19 +114,17 @@ export default MarkerView.extend({
         updateMarkerLayout(mpModel.getData(), seriesModel, api);
 
         mpData.each(function (idx) {
-            var itemModel = mpData.getItemModel(idx);
+            var itemModel = mpData.getItemModel<MarkPointDataItemOption>(idx);
             var symbol = itemModel.getShallow('symbol');
             var symbolSize = itemModel.getShallow('symbolSize');
-            var isFnSymbol = zrUtil.isFunction(symbol);
-            var isFnSymbolSize = zrUtil.isFunction(symbolSize);
 
-            if (isFnSymbol || isFnSymbolSize) {
+            if (isFunction(symbol) || isFunction(symbolSize)) {
                 var rawIdx = mpModel.getRawValue(idx);
                 var dataParams = mpModel.getDataParams(idx);
-                if (isFnSymbol) {
+                if (isFunction(symbol)) {
                     symbol = symbol(rawIdx, dataParams);
                 }
-                if (isFnSymbolSize) {
+                if (isFunction(symbolSize)) {
                     // FIXME 这里不兼容 ECharts 2.x,2.x 貌似参数是整个数据?
                     symbolSize = symbolSize(rawIdx, dataParams);
                 }
@@ -124,7 +133,7 @@ export default MarkerView.extend({
             mpData.setItemVisual(idx, {
                 symbol: symbol,
                 symbolSize: symbolSize,
-                color: itemModel.get('itemStyle.color')
+                color: itemModel.get(['itemStyle', 'color'])
                     || seriesData.getVisual('color')
             });
         });
@@ -137,31 +146,29 @@ export default MarkerView.extend({
         // FIXME
         mpData.eachItemGraphicEl(function (el) {
             el.traverse(function (child) {
-                child.dataModel = mpModel;
+                getECData(child).dataModel = mpModel;
             });
         });
 
-        symbolDraw.__keep = true;
+        this.markKeep(symbolDraw);
 
         symbolDraw.group.silent = mpModel.get('silent') || seriesModel.get('silent');
     }
-});
-
-/**
- * @inner
- * @param {module:echarts/coord/*} [coordSys]
- * @param {module:echarts/model/Series} seriesModel
- * @param {module:echarts/model/Model} mpModel
- */
-function createList(coordSys, seriesModel, mpModel) {
+}
+
+function createList(
+    coordSys: CoordinateSystem,
+    seriesModel: SeriesModel,
+    mpModel: MarkPointModel
+) {
     var coordDimsInfos;
     if (coordSys) {
-        coordDimsInfos = zrUtil.map(coordSys && coordSys.dimensions, function (coordDim) {
+        coordDimsInfos = map(coordSys && coordSys.dimensions, function (coordDim) {
             var info = seriesModel.getData().getDimensionInfo(
                 seriesModel.getData().mapDimension(coordDim)
             ) || {};
             // In map series data don't have lng and lat dimension. Fallback to same with coordSys
-            return zrUtil.defaults({name: coordDim}, info);
+            return defaults({name: coordDim}, info);
         });
     }
     else {
@@ -172,20 +179,22 @@ function createList(coordSys, seriesModel, mpModel) {
     }
 
     var mpData = new List(coordDimsInfos, mpModel);
-    var dataOpt = zrUtil.map(mpModel.get('data'), zrUtil.curry(
+    var dataOpt = map(mpModel.get('data'), curry(
             markerHelper.dataTransform, seriesModel
         ));
     if (coordSys) {
-        dataOpt = zrUtil.filter(
-            dataOpt, zrUtil.curry(markerHelper.dataFilter, coordSys)
+        dataOpt = filter(
+            dataOpt, curry(markerHelper.dataFilter, coordSys)
         );
     }
 
     mpData.initData(dataOpt, null,
-        coordSys ? markerHelper.dimValueGetter : function (item) {
+        coordSys ? markerHelper.dimValueGetter : function (item: MarkPointDataItemOption) {
             return item.value;
         }
     );
 
     return mpData;
 }
+
+ComponentView.registerClass(MarkPointView);
\ No newline at end of file
diff --git a/src/component/marker/MarkerModel.ts b/src/component/marker/MarkerModel.ts
index d7269bc..5374dba 100644
--- a/src/component/marker/MarkerModel.ts
+++ b/src/component/marker/MarkerModel.ts
@@ -17,32 +17,108 @@
 * under the License.
 */
 
-// @ts-nocheck
-
 import {__DEV__} from '../../config';
-import * as echarts from '../../echarts';
 import * as zrUtil from 'zrender/src/core/util';
 import env from 'zrender/src/core/env';
-import * as modelUtil from '../../util/model';
 import * as formatUtil from '../../util/format';
 import DataFormatMixin from '../../model/mixin/dataFormat';
+import ComponentModel from '../../model/Component';
+import SeriesModel from '../../model/Series';
+import {
+    DisplayStateHostOption,
+    ComponentOption,
+    AnimationOptionMixin,
+    Dictionary,
+    CommonTooltipOption,
+    ScaleDataValue
+} from '../../util/types';
+import Model from '../../model/Model';
+import GlobalModel from '../../model/Global';
+import List from '../../data/List';
+import { makeInner, defaultEmphasis } from '../../util/model';
 
 var addCommas = formatUtil.addCommas;
 var encodeHTML = formatUtil.encodeHTML;
 
-function fillLabel(opt) {
-    modelUtil.defaultEmphasis(opt, 'label', ['show']);
+function fillLabel(opt: DisplayStateHostOption) {
+    defaultEmphasis(opt, 'label', ['show']);
 }
-var MarkerModel = echarts.extendComponentModel({
 
-    type: 'marker',
+export type MarkerStatisticType = 'average' | 'min' | 'max' | 'median';
+
+/**
+ * Option to specify where to put the marker.
+ */
+export interface MarkerPositionOption {
+    // Priority: x/y > coord(xAxis, yAxis) > type
+
+    // Absolute position, px or percent string
+    x?: number | string
+    y?: number | string
+
+    /**
+     * Coord on any coordinate system
+     */
+    coord?: (ScaleDataValue | MarkerStatisticType)[]
+
+    // On cartesian coordinate system
+    xAxis?: ScaleDataValue
+    yAxis?: ScaleDataValue
+
+    // On polar coordinate system
+    radiusAxis?: ScaleDataValue
+    angleAxis?: ScaleDataValue
+
+    // Use statistic method
+    type?: MarkerStatisticType
+    /**
+     * When using statistic method with type.
+     * valueIndex and valueDim can be specify which dim the statistic is used on.
+     */
+    valueIndex?: number
+    valueDim?: string
 
-    dependencies: ['series', 'grid', 'polar', 'geo'],
+
+    /**
+     * Value to be displayed as label. Totally optional
+     */
+    value?: string | number
+}
+
+export interface MarkerOption extends ComponentOption, AnimationOptionMixin {
+
+    silent?: boolean
+
+    data?: unknown[]
+
+    tooltip?: CommonTooltipOption<unknown> & {
+        trigger?: 'item' | 'axis' | boolean | 'none'
+    }
+}
+
+// { [componentType]: MarkerModel }
+const inner = makeInner<Dictionary<MarkerModel>, SeriesModel>();
+
+abstract class MarkerModel<Opts extends MarkerOption = MarkerOption> extends ComponentModel<Opts> {
+
+    static type = 'marker'
+    type = MarkerModel.type
+
+    /**
+     * If marker model is created by self from series
+     */
+    createdBySelf = false
+
+    static readonly dependencies = ['series', 'grid', 'polar', 'geo']
+
+    __hostSeries: SeriesModel
+
+    private _data: List
 
     /**
      * @overrite
      */
-    init: function (option, parentModel, ecModel) {
+    init(option: Opts, parentModel: Model, ecModel: GlobalModel) {
 
         if (__DEV__) {
             if (this.type === 'marker') {
@@ -51,38 +127,37 @@ var MarkerModel = echarts.extendComponentModel({
         }
         this.mergeDefaultAndTheme(option, ecModel);
         this._mergeOption(option, ecModel, false, true);
-    },
+    }
 
-    /**
-     * @return {boolean}
-     */
-    isAnimationEnabled: function () {
+    isAnimationEnabled(): boolean {
         if (env.node) {
             return false;
         }
 
         var hostSeries = this.__hostSeries;
         return this.getShallow('animation') && hostSeries && hostSeries.isAnimationEnabled();
-    },
+    }
 
     /**
      * @overrite
      */
-    mergeOption: function (newOpt, ecModel) {
+    mergeOption(newOpt: Opts, ecModel: GlobalModel) {
         this._mergeOption(newOpt, ecModel, false, false);
-    },
+    }
 
-    _mergeOption: function (newOpt, ecModel, createdBySelf, isInit) {
-        var MarkerModel = this.constructor;
-        var modelPropName = this.mainType + 'Model';
+    _mergeOption(newOpt: Opts, ecModel: GlobalModel, createdBySelf?: boolean, isInit?: boolean) {
+        var componentType = this.mainType;
         if (!createdBySelf) {
             ecModel.eachSeries(function (seriesModel) {
 
-                var markerOpt = seriesModel.get(this.mainType, true);
+                // mainType can be markPoint, markLine, markArea
+                var markerOpt = seriesModel.get(
+                    this.mainType as any, true
+                ) as Opts;
 
-                var markerModel = seriesModel[modelPropName];
+                var markerModel = inner(seriesModel)[componentType];
                 if (!markerOpt || !markerOpt.data) {
-                    seriesModel[modelPropName] = null;
+                    inner(seriesModel)[componentType] = null;
                     return;
                 }
                 if (!markerModel) {
@@ -101,9 +176,12 @@ var MarkerModel = echarts.extendComponentModel({
                         }
                     });
 
-                    markerModel = new MarkerModel(
+                    markerModel = this.createMarkerModelFromSeries(
                         markerOpt, this, ecModel
                     );
+                    // markerModel = new ImplementedMarkerModel(
+                    //     markerOpt, this, ecModel
+                    // );
 
                     zrUtil.extend(markerModel, {
                         mainType: this.mainType,
@@ -118,16 +196,16 @@ var MarkerModel = echarts.extendComponentModel({
                 else {
                     markerModel._mergeOption(markerOpt, ecModel, true);
                 }
-                seriesModel[modelPropName] = markerModel;
+                inner(seriesModel)[componentType] = markerModel;
             }, this);
         }
-    },
+    }
 
-    formatTooltip: function (dataIndex) {
+    formatTooltip(dataIndex: number) {
         var data = this.getData();
         var value = this.getRawValue(dataIndex);
         var formattedValue = zrUtil.isArray(value)
-            ? zrUtil.map(value, addCommas).join(', ') : addCommas(value);
+            ? zrUtil.map(value, addCommas).join(', ') : addCommas(value as number);
         var name = data.getName(dataIndex);
         var html = encodeHTML(this.name);
         if (value != null || name) {
@@ -143,17 +221,35 @@ var MarkerModel = echarts.extendComponentModel({
             html += encodeHTML(formattedValue);
         }
         return html;
-    },
+    }
 
-    getData: function () {
-        return this._data;
-    },
+    getData(): List<this> {
+        return this._data as List<this>;
+    }
 
-    setData: function (data) {
+    setData(data: List) {
         this._data = data;
     }
-});
 
+    /**
+     * Create slave marker model from series.
+     */
+    abstract createMarkerModelFromSeries(
+        markerOpt: Opts,
+        masterMarkerModel: MarkerModel,
+        ecModel: GlobalModel
+    ): MarkerModel
+
+    static getMarkerModelFromSeries(
+        seriesModel: SeriesModel,
+        // Support three types of markers. Strict check.
+        componentType: 'markLine' | 'markPoint' | 'markArea'
+    ) {
+        return inner(seriesModel)[componentType];
+    }
+}
+
+interface MarkerModel<Opts extends MarkerOption = MarkerOption> extends DataFormatMixin {}
 zrUtil.mixin(MarkerModel, DataFormatMixin.prototype);
 
 export default MarkerModel;
\ No newline at end of file
diff --git a/src/component/marker/MarkerView.ts b/src/component/marker/MarkerView.ts
index 1aaecf8..bf9a33d 100644
--- a/src/component/marker/MarkerView.ts
+++ b/src/component/marker/MarkerView.ts
@@ -17,40 +17,65 @@
 * under the License.
 */
 
-// @ts-nocheck
+import ComponentView from '../../view/Component';
+import { HashMap, createHashMap } from 'zrender/src/core/util';
+import MarkerModel from './MarkerModel';
+import GlobalModel from '../../model/Global';
+import ExtensionAPI from '../../ExtensionAPI';
+import { makeInner } from '../../util/model';
+import SeriesModel from '../../model/Series';
+import { Group } from 'zrender/src/export';
 
-import * as echarts from '../../echarts';
-import * as zrUtil from 'zrender/src/core/util';
+const inner = makeInner<{
+    keep: boolean
+}, MarkerDraw>();
 
-export default echarts.extendComponentView({
+interface MarkerDraw {
+    group: Group
+}
+abstract class MarkerView extends ComponentView {
 
-    type: 'marker',
+    static type = 'marker'
+    type = MarkerView.type
 
-    init: function () {
-        /**
-         * Markline grouped by series
-         * @private
-         * @type {module:zrender/core/util.HashMap}
-         */
-        this.markerGroupMap = zrUtil.createHashMap();
-    },
+    /**
+     * Markline grouped by series
+     */
+    markerGroupMap: HashMap<MarkerDraw>
 
-    render: function (markerModel, ecModel, api) {
+    init() {
+        this.markerGroupMap = createHashMap();
+    }
+
+    render(markerModel: MarkerModel, ecModel: GlobalModel, api: ExtensionAPI) {
         var markerGroupMap = this.markerGroupMap;
         markerGroupMap.each(function (item) {
-            item.__keep = false;
+            inner(item).keep = false;
         });
 
-        var markerModelKey = this.type + 'Model';
         ecModel.eachSeries(function (seriesModel) {
-            var markerModel = seriesModel[markerModelKey];
+            var markerModel = MarkerModel.getMarkerModelFromSeries(
+                seriesModel,
+                this.type as 'markPoint' | 'markLine' | 'markArea'
+            );
             markerModel && this.renderSeries(seriesModel, markerModel, ecModel, api);
         }, this);
 
         markerGroupMap.each(function (item) {
-            !item.__keep && this.group.remove(item.group);
+            !inner(item).keep && this.group.remove(item.group);
         }, this);
-    },
+    }
+
+    markKeep(drawGroup: MarkerDraw) {
+        inner(drawGroup).keep = true;
+    }
+
+    abstract renderSeries(
+        seriesModel: SeriesModel,
+        markerModel: MarkerModel,
+        ecModel: GlobalModel,
+        api: ExtensionAPI
+    ): void
+}
 
-    renderSeries: function () {}
-});
\ No newline at end of file
+export default MarkerView;
\ No newline at end of file
diff --git a/src/component/marker/markerHelper.ts b/src/component/marker/markerHelper.ts
index e57bb17..f288607 100644
--- a/src/component/marker/markerHelper.ts
+++ b/src/component/marker/markerHelper.ts
@@ -17,20 +17,29 @@
 * under the License.
 */
 
-// @ts-nocheck
-
-import * as zrUtil from 'zrender/src/core/util';
 import * as numberUtil from '../../util/number';
 import {isDimensionStacked} from '../../data/helper/dataStackHelper';
+import SeriesModel from '../../model/Series';
+import List from '../../data/List';
+import { MarkerStatisticType, MarkerPositionOption } from './MarkerModel';
+import { indexOf, curry, clone, isArray } from 'zrender/src/core/util';
+import Axis from '../../coord/Axis';
+import { CoordinateSystem } from '../../coord/CoordinateSystem';
+import { ScaleDataValue, ParsedValue } from '../../util/types';
 
-var indexOf = zrUtil.indexOf;
+interface MarkerAxisInfo {
+    valueDataDim: string
+    valueAxis: Axis
+    baseAxis: Axis
+    baseDataDim: string
+}
 
-function hasXOrY(item) {
-    return !(isNaN(parseFloat(item.x)) && isNaN(parseFloat(item.y)));
+function hasXOrY(item: MarkerPositionOption) {
+    return !(isNaN(parseFloat(item.x as string)) && isNaN(parseFloat(item.y as string)));
 }
 
-function hasXAndY(item) {
-    return !isNaN(parseFloat(item.x)) && !isNaN(parseFloat(item.y));
+function hasXAndY(item: MarkerPositionOption) {
+    return !isNaN(parseFloat(item.x as string)) && !isNaN(parseFloat(item.y as string));
 }
 
 // Make it simple, do not visit all stacked value to count precision.
@@ -58,16 +67,21 @@ function hasXAndY(item) {
 // }
 
 function markerTypeCalculatorWithExtent(
-    mlType, data, otherDataDim, targetDataDim, otherCoordIndex, targetCoordIndex
-) {
-    var coordArr = [];
+    markerType: MarkerStatisticType,
+    data: List,
+    otherDataDim: string,
+    targetDataDim: string,
+    otherCoordIndex: number,
+    targetCoordIndex: number
+): [ParsedValue[], ParsedValue] {
+    var coordArr: ParsedValue[] = [];
 
     var stacked = isDimensionStacked(data, targetDataDim /*, otherDataDim*/);
     var calcDataDim = stacked
         ? data.getCalculationInfo('stackResultDimension')
         : targetDataDim;
 
-    var value = numCalculate(data, calcDataDim, mlType);
+    var value = numCalculate(data, calcDataDim, markerType);
 
     var dataIndex = data.indicesOfNearest(calcDataDim, value)[0];
     coordArr[otherCoordIndex] = data.get(otherDataDim, dataIndex);
@@ -77,37 +91,18 @@ function markerTypeCalculatorWithExtent(
     var precision = numberUtil.getPrecision(data.get(targetDataDim, dataIndex));
     precision = Math.min(precision, 20);
     if (precision >= 0) {
-        coordArr[targetCoordIndex] = +coordArr[targetCoordIndex].toFixed(precision);
+        coordArr[targetCoordIndex] = +(coordArr[targetCoordIndex] as number).toFixed(precision);
     }
 
     return [coordArr, coordArrValue];
 }
 
-var curry = zrUtil.curry;
 // TODO Specified percent
 var markerTypeCalculator = {
-    /**
-     * @method
-     * @param {module:echarts/data/List} data
-     * @param {string} baseAxisDim
-     * @param {string} valueAxisDim
-     */
     min: curry(markerTypeCalculatorWithExtent, 'min'),
-    /**
-     * @method
-     * @param {module:echarts/data/List} data
-     * @param {string} baseAxisDim
-     * @param {string} valueAxisDim
-     */
     max: curry(markerTypeCalculatorWithExtent, 'max'),
-
-    /**
-     * @method
-     * @param {module:echarts/data/List} data
-     * @param {string} baseAxisDim
-     * @param {string} valueAxisDim
-     */
-    average: curry(markerTypeCalculatorWithExtent, 'average')
+    average: curry(markerTypeCalculatorWithExtent, 'average'),
+    median: curry(markerTypeCalculatorWithExtent, 'median')
 };
 
 /**
@@ -119,7 +114,10 @@ var markerTypeCalculator = {
  * @param  {Object} item
  * @return {Object}
  */
-export function dataTransform(seriesModel, item) {
+export function dataTransform(
+    seriesModel: SeriesModel,
+    item: MarkerPositionOption
+) {
     var data = seriesModel.getData();
     var coordSys = seriesModel.coordinateSystem;
 
@@ -128,13 +126,13 @@ export function dataTransform(seriesModel, item) {
     // `yAxis` to specify the coord on each dimension
 
     // parseFloat first because item.x and item.y can be percent string like '20%'
-    if (item && !hasXAndY(item) && !zrUtil.isArray(item.coord) && coordSys) {
+    if (item && !hasXAndY(item) && !isArray(item.coord) && coordSys) {
         var dims = coordSys.dimensions;
         var axisInfo = getAxisInfo(item, data, coordSys, seriesModel);
 
         // Clone the option
         // Transform the properties xAxis, yAxis, radiusAxis, angleAxis, geoCoord to value
-        item = zrUtil.clone(item);
+        item = clone(item);
 
         if (item.type
             && markerTypeCalculator[item.type]
@@ -161,8 +159,8 @@ export function dataTransform(seriesModel, item) {
             ];
             // Each coord support max, min, average
             for (var i = 0; i < 2; i++) {
-                if (markerTypeCalculator[coord[i]]) {
-                    coord[i] = numCalculate(data, data.mapDimension(dims[i]), coord[i]);
+                if (markerTypeCalculator[coord[i] as MarkerStatisticType]) {
+                    coord[i] = numCalculate(data, data.mapDimension(dims[i]), coord[i] as MarkerStatisticType);
                 }
             }
             item.coord = coord;
@@ -171,8 +169,13 @@ export function dataTransform(seriesModel, item) {
     return item;
 }
 
-export function getAxisInfo(item, data, coordSys, seriesModel) {
-    var ret = {};
+export function getAxisInfo(
+    item: MarkerPositionOption,
+    data: List,
+    coordSys: CoordinateSystem,
+    seriesModel: SeriesModel
+) {
+    var ret = {} as MarkerAxisInfo;
 
     if (item.valueIndex != null || item.valueDim != null) {
         ret.valueDataDim = item.valueIndex != null
@@ -191,7 +194,7 @@ export function getAxisInfo(item, data, coordSys, seriesModel) {
     return ret;
 }
 
-function dataDimToCoordDim(seriesModel, dataDim) {
+function dataDimToCoordDim(seriesModel: SeriesModel, dataDim: string) {
     var data = seriesModel.getData();
     var dimensions = data.dimensions;
     dataDim = data.getDimension(dataDim);
@@ -206,29 +209,41 @@ function dataDimToCoordDim(seriesModel, dataDim) {
 /**
  * Filter data which is out of coordinateSystem range
  * [dataFilter description]
- * @param  {module:echarts/coord/*} [coordSys]
- * @param  {Object} item
- * @return {boolean}
  */
-export function dataFilter(coordSys, item) {
+export function dataFilter(
+    // Currently only polar and cartesian has containData.
+    coordSys: CoordinateSystem & {
+        containData?(data: ScaleDataValue[]): boolean
+    },
+    item: MarkerPositionOption
+) {
     // Alwalys return true if there is no coordSys
     return (coordSys && coordSys.containData && item.coord && !hasXOrY(item))
         ? coordSys.containData(item.coord) : true;
 }
 
-export function dimValueGetter(item, dimName, dataIndex, dimIndex) {
+export function dimValueGetter(
+    item: MarkerPositionOption,
+    dimName: string,
+    dataIndex: number,
+    dimIndex: number
+) {
     // x, y, radius, angle
     if (dimIndex < 2) {
-        return item.coord && item.coord[dimIndex];
+        return item.coord && item.coord[dimIndex] as ParsedValue;
     }
     return item.value;
 }
 
-export function numCalculate(data, valueDataDim, type) {
+export function numCalculate(
+    data: List,
+    valueDataDim: string,
+    type: MarkerStatisticType
+) {
     if (type === 'average') {
         var sum = 0;
         var count = 0;
-        data.each(valueDataDim, function (val, idx) {
+        data.each(valueDataDim, function (val: number, idx) {
             if (!isNaN(val)) {
                 sum += val;
                 count++;
@@ -241,6 +256,6 @@ export function numCalculate(data, valueDataDim, type) {
     }
     else {
         // max & min
-        return data.getDataExtent(valueDataDim, true)[type === 'max' ? 1 : 0];
+        return data.getDataExtent(valueDataDim)[type === 'max' ? 1 : 0];
     }
 }
diff --git a/src/component/visualMap/VisualMapModel.ts b/src/component/visualMap/VisualMapModel.ts
index 99c3037..e08486e 100644
--- a/src/component/visualMap/VisualMapModel.ts
+++ b/src/component/visualMap/VisualMapModel.ts
@@ -613,6 +613,4 @@ class VisualMapModel<Opts extends VisualMapOption = VisualMapOption> extends Com
     }
 }
 
-ComponentModel.registerClass(VisualMapModel);
-
 export default VisualMapModel;
diff --git a/src/coord/CoordinateSystem.ts b/src/coord/CoordinateSystem.ts
index 1c1360e..96f1373 100644
--- a/src/coord/CoordinateSystem.ts
+++ b/src/coord/CoordinateSystem.ts
@@ -161,3 +161,9 @@ export interface CoordinateSystemHostModel extends ComponentModel {
 export interface CoordinateSystemClipArea {
     contain(x: number, y: number): boolean
 }
+
+export function isCoordinateSystemType<T extends CoordinateSystem, S = T['type']>(
+    coordSys: CoordinateSystem, type: S
+): coordSys is T {
+    return (coordSys.type as unknown as S) === type;
+}
diff --git a/src/coord/axisCommonTypes.ts b/src/coord/axisCommonTypes.ts
index 046a055..69cd000 100644
--- a/src/coord/axisCommonTypes.ts
+++ b/src/coord/axisCommonTypes.ts
@@ -19,7 +19,7 @@
 
 import {
     TextCommonOption, LineStyleOption, OrdinalRawValue, ZRColor,
-    AreaStyleOption, ComponentOption, OptionDataValue, ColorString,
+    AreaStyleOption, ComponentOption, ColorString,
     AnimationOptionMixin, Dictionary
 } from '../util/types';
 
diff --git a/src/coord/geo/geoJSONLoader.ts b/src/coord/geo/geoJSONLoader.ts
index 4e7df3e..7e49f4e 100644
--- a/src/coord/geo/geoJSONLoader.ts
+++ b/src/coord/geo/geoJSONLoader.ts
@@ -37,7 +37,7 @@ type MapRecordInner = {
     };
 };
 
-var inner = makeInner<MapRecordInner>();
+var inner = makeInner<MapRecordInner, GeoJSONMapRecord>();
 
 export default {
 
diff --git a/src/coord/geo/geoSVGLoader.ts b/src/coord/geo/geoSVGLoader.ts
index 24b978c..3d37e31 100644
--- a/src/coord/geo/geoSVGLoader.ts
+++ b/src/coord/geo/geoSVGLoader.ts
@@ -33,7 +33,7 @@ type MapRecordInner = {
     originRootHostKey: string;
 };
 
-var inner = makeInner<MapRecordInner>();
+var inner = makeInner<MapRecordInner, SVGMapRecord>();
 
 export default {
 
diff --git a/src/coord/polar/AngleAxis.ts b/src/coord/polar/AngleAxis.ts
index b5dbaa4..8444a9f 100644
--- a/src/coord/polar/AngleAxis.ts
+++ b/src/coord/polar/AngleAxis.ts
@@ -28,7 +28,7 @@ import { AngleAxisModel } from './AxisModel';
 var inner = makeInner<{
     lastAutoInterval: number
     lastTickCount: number
-}>();
+}, AngleAxisModel>();
 
 interface AngleAxis {
     dataToAngle: Axis['dataToCoord']
diff --git a/src/data/DataDimensionInfo.ts b/src/data/DataDimensionInfo.ts
index cc15369..abab572 100644
--- a/src/data/DataDimensionInfo.ts
+++ b/src/data/DataDimensionInfo.ts
@@ -28,7 +28,7 @@ class DataDimensionInfo {
      * `dataCtors` of `data/List`.
      * Optional.
      */
-    type: DimensionType;
+    type?: DimensionType;
 
     /**
      * Dimension name.
diff --git a/src/data/List.ts b/src/data/List.ts
index bdf2994..27bc354 100644
--- a/src/data/List.ts
+++ b/src/data/List.ts
@@ -748,13 +748,13 @@ class List<HostModel extends Model = Model> {
      * @param dimensions If ignored, using all dimensions.
      */
     getValues(idx: number): ParsedValue[];
-    getValues(dimensions: DimensionName[], idx: number): ParsedValue[];
-    getValues(dimensions: DimensionName[] | number, idx?: number): ParsedValue[] {
+    getValues(dimensions: readonly DimensionName[], idx: number): ParsedValue[];
+    getValues(dimensions: readonly DimensionName[] | number, idx?: number): ParsedValue[] {
         var values = [];
 
         if (!zrUtil.isArray(dimensions)) {
             // stack = idx;
-            idx = dimensions;
+            idx = dimensions as number;
             dimensions = this.dimensions;
         }
 
@@ -894,11 +894,9 @@ class List<HostModel extends Model = Model> {
 
         // TODO
         // Use quick select?
-
-        // immutability & sort
-        var sortedDimDataArray = [].concat(dimDataArray).sort(function (a, b) {
+        var sortedDimDataArray = dimDataArray.sort(function (a: number, b: number) {
             return a - b;
-        });
+        }) as number[];
         var len = this.count();
         // calculate median
         return len === 0
diff --git a/src/model/Component.ts b/src/model/Component.ts
index 31c3782..ada5ac9 100644
--- a/src/model/Component.ts
+++ b/src/model/Component.ts
@@ -43,7 +43,7 @@ import {
 
 var inner = makeInner<{
     defaultOption: ComponentOption
-}>();
+}, ComponentModel>();
 
 class ComponentModel<Opt extends ComponentOption = ComponentOption> extends Model<Opt> {
 
diff --git a/src/model/Model.ts b/src/model/Model.ts
index 86763ac..e0b4c31 100644
--- a/src/model/Model.ts
+++ b/src/model/Model.ts
@@ -36,7 +36,9 @@ import { ModelOption } from '../util/types';
 import { Dictionary } from 'zrender/src/core/types';
 
 var mixin = zrUtil.mixin;
-var inner = makeInner<{getParent(path: string | string[]): Model}>();
+var inner = makeInner<{
+    getParent(path: string | string[]): Model
+}, Model>();
 
 // Since model.option can be not only `Dictionary` but also primary types,
 // we do this conditional type to avoid getting type 'never';
diff --git a/src/model/Series.ts b/src/model/Series.ts
index 7938308..7b6c569 100644
--- a/src/model/Series.ts
+++ b/src/model/Series.ts
@@ -59,7 +59,7 @@ import { GradientObject } from 'zrender/src/graphic/Gradient';
 var inner = modelUtil.makeInner<{
     data: List
     dataBeforeProcessed: List
-}>();
+}, SeriesModel>();
 
 interface SeriesModel {
     /**
@@ -86,6 +86,11 @@ interface SeriesModel {
         dataIndices: number[],
         nestestValue: any
     };
+
+    /**
+     * Get position for marker
+     */
+    getMarkerPosition(value: ScaleDataValue[]): number[]
 }
 
 class SeriesModel<Opt extends SeriesOption = SeriesOption> extends ComponentModel<Opt> {
diff --git a/src/model/mixin/colorPalette.ts b/src/model/mixin/colorPalette.ts
index 510e731..4d1f16e 100644
--- a/src/model/mixin/colorPalette.ts
+++ b/src/model/mixin/colorPalette.ts
@@ -25,7 +25,7 @@ import { Dictionary } from 'zrender/src/core/types';
 var inner = makeInner<{
     colorIdx: number
     colorNameMap: Dictionary<ZRColor>
-}>();
+}, ColorPaletteMixin>();
 
 function getNearestColorPalette(
     colors: ZRColor[][], requestColorNum: number
diff --git a/src/util/graphic.ts b/src/util/graphic.ts
index 9a391d8..e936fd2 100644
--- a/src/util/graphic.ts
+++ b/src/util/graphic.ts
@@ -1540,7 +1540,7 @@ export interface ECData {
     dataType?: string;
 }
 
-export const getECData = makeInner<ECData>();
+export const getECData = makeInner<ECData, Element>();
 
 // Register built-in shapes. These shapes might be overwirtten
 // by users, although we do not recommend that.
diff --git a/src/util/model.ts b/src/util/model.ts
index 7e27006..be9e3e9 100644
--- a/src/util/model.ts
+++ b/src/util/model.ts
@@ -466,14 +466,14 @@ export function queryDataIndex(data: List, payload: Payload & {
  *
  * @return {Function}
  */
-export function makeInner<T>() {
-    // Consider different scope by es module import.
-    var key = '__\0ec_inner_' + innerUniqueIndex++ + '_' + Math.random().toFixed(5);
-    return function (hostObj: any): T {
-        return hostObj[key] || (hostObj[key] = {});
+export function makeInner<T, Host extends object>() {
+    var key = '__ec_inner_' + innerUniqueIndex++;
+    return function (hostObj: Host): T {
+        return (hostObj as any)[key] || ((hostObj as any)[key] = {});
     };
 }
-var innerUniqueIndex = 0;
+// A random start point.
+var innerUniqueIndex = Math.round(Math.random() * 5);
 
 /**
  * If string, e.g., 'geo', means {geoIndex: 0}.
diff --git a/src/util/types.ts b/src/util/types.ts
index fe0d20d..12579f8 100644
--- a/src/util/types.ts
+++ b/src/util/types.ts
@@ -763,6 +763,16 @@ export interface LabelOption extends TextCommonOption {
  * Option for labels on line, like markLine, lines
  */
 export interface LineLabelOption extends Omit<LabelOption, 'distance'> {
+    position?: 'start'
+        | 'middle'
+        | 'end'
+        | 'insideStartTop'
+        | 'insideStartBottom'
+        | 'insideMiddleTop'
+        | 'insideMiddleBottom'
+        | 'insideEndTop'
+        | 'insideEndBottom'
+        | 'insideMiddleBottom'
     /**
      * Distance can be an array.
      * Which will specify horizontal and vertical distance respectively
diff --git a/src/view/Chart.ts b/src/view/Chart.ts
index f0343ea..8810e74 100644
--- a/src/view/Chart.ts
+++ b/src/view/Chart.ts
@@ -38,7 +38,7 @@ import List from '../data/List';
 
 var inner = modelUtil.makeInner<{
     updateMethod: keyof ChartView
-}>();
+}, Payload>();
 var renderPlanner = createRenderPlanner();
 
 interface ChartView {
diff --git a/src/view/Component.ts b/src/view/Component.ts
index f695505..69febfe 100644
--- a/src/view/Component.ts
+++ b/src/view/Component.ts
@@ -26,6 +26,24 @@ import ExtensionAPI from '../ExtensionAPI';
 import {Payload, ViewRootGroup, ECEvent, EventQueryItem} from '../util/types';
 import Element from 'zrender/src/Element';
 
+interface ComponentView {
+    /**
+     * Implement it if needed.
+     */
+    updateTransform(
+        seriesModel: ComponentModel, ecModel: GlobalModel, api: ExtensionAPI, payload: Payload
+    ): void | {update: true};
+
+    /**
+     * Pass only when return `true`.
+     * Implement it if needed.
+     */
+    filterForExposedEvent(
+        eventType: string, query: EventQueryItem, targetEl: Element, packedEvent: ECEvent
+    ): boolean;
+}
+
+
 class ComponentView {
 
     // [Caution]: for compat the previous "class extend"
@@ -56,14 +74,6 @@ class ComponentView {
 
     dispose(ecModel: GlobalModel, api: ExtensionAPI): void {}
 
-    /**
-     * Pass only when return `true`.
-     * Implement it if needed.
-     */
-    filterForExposedEvent: (
-        eventType: string, query: EventQueryItem, targetEl: Element, packedEvent: ECEvent
-    ) => boolean;
-
     updateView(model: ComponentModel, ecModel: GlobalModel, api: ExtensionAPI, payload: Payload): void {
         // Do nothing;
     }
@@ -76,13 +86,6 @@ class ComponentView {
         // Do nothing;
     }
 
-    /**
-     * Implement it if needed.
-     */
-    updateTransform: (
-        seriesModel: ComponentModel, ecModel: GlobalModel, api: ExtensionAPI, payload: Payload
-    ) => void | {update: true};
-
     static registerClass: clazzUtil.ClassManager['registerClass'];
 };
 


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