Использование типа any
в TypeScript отключает проверки типов, что не желательно. Также в наиболее строгом режиме с помощью "strict": true
в tsconfig.json
использование any
невозможно. А это значительно повышает безопасность кода.
При этом бывают ситуации, когда тип неизвестен, но работа с ним должна быть безопасна с точки зрения типов. Для этого в TypeScript существует дополнение к any
— 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
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Ваше упражнение проверяется по этим тестам
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
Решение учителя откроется через: