```
import { Axis } from 'highcharts';

import { AdditionalProperties, MeasurementUnit, UnitProperties } from '~/api';
import { getRoundUpToValue, getRoundingValue } from '~/utils';

import { ExtendedAxis, ExtendedSeriesOptions, ExtendedSeriesOptionsType } from '../types';

const TICK_MAX_COUNT = 10;
const DEFAULT_INTERVAL = 1;
const MIN_INTERVAL = 0.01;
const DEFAULT_SERIES = 'defaultSeries';
const limits = new Map();

function getIntervalTick(delta: number, step: number): number {
  let tickCount = delta / step;
  let tick = 0;
  let newStep = step;

  if (tickCount > TICK_MAX_COUNT) {
    while (tickCount > TICK_MAX_COUNT) {
      tick += newStep;
      tickCount = delta / tick;
    }
  } else if (tickCount < TICK_MAX_COUNT / 2) {
    newStep /= 10;
    return getIntervalTick(delta, newStep);
  } else {
    tick = newStep;
  }

  return tick;
}

function getTick(delta: number, accuracy: number) {
  let step = DEFAULT_INTERVAL;

  if (delta < MIN_INTERVAL) {
    return step;
  }
  const interval = delta / TICK_MAX_COUNT;

  if (step < interval) {
    while (step * 10 < delta) {
      step *= 10;
    }
  } else {
    while (step * 10 > delta) {
      step /= 10;
    }
  }

  const tick = getIntervalTick(delta, step);
  const accuracyTick = 10 ** -accuracy;

  if (tick < accuracyTick) {
    return accuracyTick;
  }

  return tick;
}

const getAccuracyFromAxis = (axis: ExtendedAxis): number => {
  const { chart } = axis || {};
  const { series } = chart || {};
  const [firstSeries] = series || [];
  const { options } = firstSeries || {};
  const { measurementUnit = {} as MeasurementUnit, properties } = (options as ExtendedSeriesOptionsType) || {};
  const { accuracy = 1 } = measurementUnit || {};
  const { physicalValue, originalParameterUnit } = properties || ({} as UnitProperties);

  return getRoundUpToValue(physicalValue, originalParameterUnit, accuracy);
};

export function linearTickPositioner(this: Axis): number[] {
  let positions: number[] = [];
  let min;
  let max;
  let name;

  const axis = this as ExtendedAxis;

  const accuracy = getAccuracyFromAxis(axis);

  const { min: userMin, max: userMax } = axis.userOptions;
  const { series } = axis;
  const [firstSeries] = series;
  if (firstSeries) {
    const { userOptions, options } = firstSeries;
    const { anomalies, fullName: paramName } = userOptions as ExtendedSeriesOptions;
    const { lowerLimit: isEnableLowerLimit, upperLimit: isEnableUpperLimit } = options as ExtendedSeriesOptions;
    if (paramName !== DEFAULT_SERIES) {
      name = paramName;
    }
    if (name) {
      limits.set(name, {
        lowerLimit: {
          dataMin: axis.dataMin,
          selected: isEnableLowerLimit,
        },
        upperLimit: {
          dataMax: axis.dataMax,
          selected: isEnableUpperLimit,
        },
      });
    }
    if (anomalies?.length) {
      const [firstAnomaly] = anomalies;
      const { algSettings, additionalProperties } = firstAnomaly;
      const { lowerLimit: lowerLimitValue, upperLimit: upperLimitValue } = algSettings;
      const { lowerRange, upperRange } = additionalProperties as AdditionalProperties;
      const curLimit = limits.get(name);
      limits.set(name, {
        lowerLimit: {
          ...curLimit.lowerLimit,
          value: lowerLimitValue || lowerRange,
        },
        upperLimit: {
          ...curLimit.upperLimit,
          value: upperLimitValue || upperRange,
        },
      });
    }
  }

  const curLimit = limits.get(name);
  const { lowerLimit, upperLimit } = curLimit || {};
  const { dataMin, selected: lowerLimitSelected, value: lowerLimitValue } = lowerLimit || {};
  const { dataMax, selected: upperLimitSelected, value: upperLimitValue } = upperLimit || {};

  if (lowerLimitSelected && upperLimitSelected) {
    min = lowerLimitValue > dataMin ? dataMin : lowerLimitValue;
    max = upperLimitValue > dataMax ? upperLimitValue : dataMax;
  } else if (lowerLimitSelected && !upperLimitSelected) {
    min = lowerLimitValue > dataMin ? dataMin : lowerLimitValue;
    max = dataMax;
  } else if (!lowerLimitSelected && upperLimitSelected) {
    if (upperLimitValue > dataMin && upperLimitValue > dataMax) {
      max = upperLimitValue;
      min = dataMin;
    }
    if (upperLimitValue > dataMin && upperLimitValue < dataMax) {
      max = dataMax;
      min = dataMin;
    }
    if (upperLimitValue < dataMin) {
      max = dataMax;
      min = upperLimitValue;
    }
  } else {
    min = dataMin;
    max = dataMax;
  }

  if (max !== null && min !== null) {
    if (userMin != null && userMax !== undefined && userMax !== null) {
      min = userMin;
      max = userMax;
    } else {
      const delta = max - min > MIN_INTERVAL * 10 ? (max - min) / 10 : MIN_INTERVAL;
      min -= delta;
      max += delta;
    }

    const tick = getTick(max - min, accuracy);

    if (min < 0) {
      // заполняем отрицательную ось ординат
      for (let nextTick = -tick; nextTick >= min; nextTick -= tick) {
        if (nextTick > min && nextTick < max) {
          positions.unshift(nextTick);
        }
      }

      positions.unshift(min);
    } else {
      positions = [min];
    }

    if (max > 0) {
      for (let nextTick = 0; nextTick <= max; nextTick += tick) {
        if (nextTick > min) {
          positions.push(nextTick);
        }
      }
    }

    positions.push(max);

    // удаляем "слипшиеся" тики
    if (Math.abs(positions[0] - positions[1]) < tick / 2 && positions.length > 2) {
      positions.splice(1, 1);
    }
    const { length } = positions;
    if (Math.abs(positions[length - 1] - positions[length - 2]) < tick / 2 && length > 2) {
      positions.splice(length - 2, 1);
    }
  }

  const result: number[] = positions
    .filter((value) => !Number.isNaN(value))
    .map((value) => getRoundingValue(value, accuracy));

  if (limits.size) {
    if (curLimit) {
      limits.set(name, {
        lowerLimit: {
          ...curLimit.lowerLimit,
          minYAxisValue: result[0],
        },
        upperLimit: {
          ...curLimit.upperLimit,
          maxYAxisValue: result[result.length - 1],
        },
      });
    }

    return result;
  }
  return [];
}

export function limitYAxisPositioner(this: Axis) {
  const axis = this as unknown as ExtendedAxis;
  const accuracy = getAccuracyFromAxis(axis);
  let curLimit;
  let min;
  let max;
  const { series } = axis;
  const [firstSeries] = series;
  if (firstSeries) {
    const { userOptions } = firstSeries;
    const { fullName } = userOptions as ExtendedSeriesOptions;
    curLimit = limits.get(fullName);
    const { lowerLimit: curLowerLimit, upperLimit: curUpperLimit } = curLimit || {};
    const { dataMin, selected: lowerLimitSelected, value: lowerLimitValue } = curLowerLimit || {};
    const { dataMax, selected: upperLimitSelected, value: upperLimitValue } = curUpperLimit || {};

    if (lowerLimitSelected && upperLimitSelected) {
      min = lowerLimitValue;
      max = upperLimitValue;
    } else if (lowerLimitSelected && !upperLimitSelected) {
      min = lowerLimitValue;
      max = dataMax;
    } else if (!lowerLimitSelected && upperLimitSelected) {
      min = dataMin;
      max = upperLimitValue;
    } else {
      min = dataMin;
      max = dataMax;
    }
  } else {
    return [];
  }

  const { upperLimit, lowerLimit } = curLimit || {};
  const { selected: upperLimitSelected, maxYAxisValue } = upperLimit || {};
  const { selected: lowerLimitSelected, minYAxisValue } = lowerLimit || {};

  const positions = [
    minYAxisValue ? getRoundingValue(minYAxisValue, accuracy) : undefined,
    upperLimitSelected && max ? getRoundingValue(max, accuracy) : undefined,
    lowerLimitSelected && min ? getRoundingValue(min, accuracy) : undefined,
    maxYAxisValue ? getRoundingValue(maxYAxisValue, accuracy) : undefined,
  ] as number[];

  return positions.filter((value) => value !== undefined);
}
```
Hi!
This code is written in typescript in the react application. 
The linearTickPositioner function describes a custom function to calculate tickPositioner in highcharts. The values in the limits variable can be different depending on the data coming from the server. limits is responsible for the upper and lower limit of the measurement range. 
limitYAxisPositioner describes a separate scale on which the values from limits are displayed. The limits themselves are common to both functions. The function getRoundingValue performs rounding of values.
Please note that the data coming from the server may not be valid and should be checked, and because of asynchronousness in react, the code may start executing before the data arrives. 

1.Optimise and refactor all this code to make it simpler, faster and clearer. Use all modern typescript functionality.
2. Add variants of linearTickPositioner function when logarithmic type is selected in highcharts. It should contain no more than 10 ticks considering the values from limits
3. Add variants of the function limitYAxisPositioner with the selected logarithmic type in highcharts. It should contain the minimum and maximum value on the chart and the upper and lower range of measurements, if any.
 Use all modern features of typescript, javascript, react. Check all new code for bugs and fix them. Remove all unused code