Typescript: Тип unknown

Использование типа any в TypeScript отключает проверки типов, что не желательно. Также в наиболее строгом режиме с помощью "strict": true в tsconfig.json использование any невозможно. А это значительно повышает безопасность кода.

При этом бывают ситуации, когда тип неизвестен, но работа с ним должна быть безопасна с точки зрения типов. Для этого в TypeScript существует дополнение к anyunknown, которое разберем в этом уроке.

Использование типа unknown

Главное отличие unknown от any связано с проверкой типов. unknown запрещает выполнять любые операции:

let value: unknown = 'code-basics';

value.toUpperCase(); // Error!
value.trim(); // Error!

Может показаться странным, что перед нами строка, но над ней нельзя выполнять строковые операции. К этому надо привыкнуть. Тип в статически типизированных языках определяется не тем, что мы видим своими глазами, а тем, как тип выводится — автоматически или через явное указание.

Переменная unknown типа нужна редко — когда нужно дальше уточнить тип. Но все меняется, когда нам нужно создать функцию, которая может работать с любым входящим типом. В JavaScript распространена подобная практика:

// Пример из lodash
_.isError(new Error); // true
_.isError(Error); // false
_.isError('code-basics'); // false

Такую функцию можно реализовать с помощью any, но тогда мы отключим проверку типов:

function isError(value: any)

Лучше использовать unknown, тогда TypeScript защитит от потенциальных ошибок типов:

function isError(value: unknown)

Затем внутри тела можно выполнить нужную проверку, чтобы узнать, с чем мы работаем:

function isError(value: unknown): boolean {
  return value instanceof Error;
}

instanceof работает только с конструкторами, поэтому в примере выше мы проверяем, является ли значение экземпляром класса Error.

Задание

Реализуйте функцию isPlainObject(), которая проверяет, является ли переданное значение объектом. Эта функция считает, что массив не объект:

isPlainObject(1); // false
isPlainObject('hexlet'); // false
isPlainObject({}); // true
isPlainObject({ name: 'code-basics' }); // true
isPlainObject([1, 8]); // false
Упражнение не проходит проверку — что делать? 😶

Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:

  • Обязательно приложите вывод тестов, без него практически невозможно понять что не так, даже если вы покажете свой код. Программисты плохо исполняют код в голове, но по полученной ошибке почти всегда понятно, куда смотреть.
В моей среде код работает, а здесь нет 🤨

Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.

Мой код отличается от решения учителя 🤔

Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.

В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.

Прочитал урок — ничего не понятно 🙄

Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.

Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.

Нашли ошибку? Есть что добавить? Пулреквесты приветствуются
Loading...

Ваше упражнение проверяется по этим тестам

1import isPlainObject from './index';
2
3test('function', () => {
4  expect(isPlainObject(3)).toBe(false);
5  expect(isPlainObject('hexlet')).toBe(false);
6  expect(isPlainObject({})).toBe(true);
7  expect(isPlainObject([])).toBe(false);
8});
9

Решение учителя откроется через:

20:00
waiting_clock