Возвращает элемент массива, удовлетворяющий указанному предикату (функции, возвращающей булевское значение) тогда и только тогда, когда такой элемент ровно 1. Если же такого элемента нет, либо их 2 и больше то:
- Будет брошена ошибка, если указано значение
{ mustThrowErrorIfElementNotFoundOrMoreThan1: true }
3-им параметром. TypeScript при этом будет верить, что функция отработала успешно, то возвращаемое значение имеет непустое значение (неnull
), а того типа, который указан (в данном случае обычно неявно) через параметр обобщения. - Если 3-ий параметр не указан, то будет
возвращён
null
. При этомTypeScript
будет требовать проверки наnull
, прежде чем можно будет полноценно пользоваться возвращённым значением.
Пример
const sample: Array<string> = [ "Saint Paul", "Santa Barbara", "St. Louis", "Santa Monica" ];
«Santa»
,
3 из них — с «Sa»
, а вот с
«St.» — только 1.
const targetCityName: string | null = getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne(
sample, (arrayElement: string): boolean => arrayElement.startsWith("St.")
);
Будет возвращён 3-ий элемент, потому что согласно предикату, нам нужен элемент, строчное значение которого начинается с «St.», а такой элемент в нашем случае только 1.
Однако, на практике содержимое массива будет заранее неизвестным. Поэтому строчный элемент, который начинается с «St.», вовсе не обязан быть один, да и вообще не обязан быть даже если таковой ожидается, потому при таком сочетании параметров функции может быть возвращён null.
console.log(targetCityName.length);
Возникнет ошибка TypeScript TS18047
(«'targetCityName' is possibly 'null'»), потому что свойство length
имеется
у строкового типа (и массивов), а переменная
targetCityName
, возможно, имеет значение
null
.
Прежде, чем вызывать у targetCityName
какие-либо строчные
свойства и/или методы (в частности
length
) необходимо доказать
TypeScript-y, что значение targetCityName
не является null
.
Сделать это можно, например, с помощью условной конструкции
if (targetCityName !== null) {}
,
тогда в пределах if-блока TypeScript будет
считать данное значение не являющимся null
.
Есть и другие решения, но чего категорически не должен делать
инженер, заявляющий владением языком TypeScript — это использовать
выражения типа targetCityName!.length
, так как это
большая трещина в качестве кода.
К тому же, обычно использование подобной токсичной функциональности имеет массовый
характер, сопровождающийся применением типа any
и
других послаблений,
сводящих на нет смысл использования языка TypeScript.
console.log(
getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne(
sample, (arrayElement: string): boolean => arrayElement.startsWith("Santa")
)
);
В данном случае возвращён null
, потому что элементов,
удовлетворяющих предикату — 2, а
не 1
.
В название функции чёрным по белому написано, что взятие элемента произойдёт
тогда и только тогда, когда предикату удовлетворяет
ровно один элемент, а в данном случае
таковых 2.
Но что если Вы уверены, что элемент, удовлетворяющий предикату, будет
ровно 1 и по-другому быть не может?
Тогда можно указать передать 3-им параметром значение
{ mustThrowErrorIfElementNotFoundOrMoreThan1: true }
— в этом случае
TypeScript не потребует проверки значения на
null
, при этом если вопреки ожиданиям предикату будет
удовлетворять не ровно 1
элемент (а вероятность этого события гораздо выше, чем кажется), то будет выброшено
исключение UnexpectedEventError
.
const matching: string = getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne(
sample,
(arrayElement: string): boolean => arrayElement.startsWith("Santa"),
{ mustThrowErrorIfElementNotFoundOrMoreThan1: true }
);
matching
как
string
, а не
string | null
, так как вместо возврата null
в случае, если элементов, удовлетворяющих предикату
0
или больше
1, будет выброшено исключение
UnexpectedEventError
.
Вы, конечно, можете обработать это исключение с помощью try/catch
,
но в общем случае это не даст никакого преимущества перед
рассмотренной выше проверкой на null
.
Сравнение с нативными методами
Приведённые ниже нативные методы не лучше и
не хуже функции
getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne
;
что именно использовать — зависит от того, какое поведение требуется с случаях, когда:
- Нет ни одного элемента массива, удовлетворяющего предикату.
- Имеется 2 и более элементов массива, удовлетворяющих предикату.
Array.prototype.find
- Общего с
getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne
у этого метода то, что оба ищут первый элемент, удовлетворяющий предикату. - Если удовлетворяющих предикату элементов нет,
Array.prototype.find
вернётundefined
, в во время какgetArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne
либо возвращаетnull
, либо бросает ошибку — в зависимости от наличия или отсутствия 3-его параметра. Если выбран вариант с бросанием ошибки, то TypeScript не будет требовать проверки наnull
— именно эта особенность может побудить использоватьgetArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne
, так как в случае сArray.prototype.find
потребуется проверка на undefined. - Если удовлетворяющих предикату элементов 2
или больше, то
Array.prototype.find
возвращает первый, а остальные — игнорирует.getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne
же, найдя удовлетворяющий предикату элемент, дополнительно проверит, не удовлетворяют ли предикату ещё какие-либо элементы, и если да, то никакой элемент не вернёт. Эта особенность полезна в тех случаях, когда надо не просто получить элемент массива по предикату, но и убедиться, что он в чём-то отличен от других, например имеет уникальный идентификатор.
Array.prototype.filter
Данный метод предназначен не для доступа к конкретному элементу массива, а для получения выборки из исходного массива. Таким образом, этот метод массива возвращает тоже массив — элементов, удовлетворяющих предикату, а не конкретный элемент.
Если же элементов, удовлетворяющих предикату нет, то будет возвращён
пустой массив.
При обращении к любому элементу этого массива
(в томи числе к первому, то есть с индексом 0) будет возвращено
значение undefined
, чего TypeScript
(да и вообще-то многие другие статически типизированные языки программирования) об этом
не предупредит.
Например, Array<string>
или
string[]
фактически означает «массив
бесконечного количества строчных элементов»,
когда в реальности любой массив конечен,
а иногда может быть пустым.
Быстрый ввод в интегрированных средах разработки семейства IntelliJ IDEA
Использование Live template-ов в семействе интегрированных сред разработки IntelliJ IDEA позволяет вводить код такой так выражения вызова функции быстрее. Для получения доступа к Live Template-ам библиотеки YDEE потребуется установить официальный плагин этой библиотеки.
Пошаговое описание процесса использования шаблона
Если Вы ранее не пользовались Live template-ами, то пусть Вас не пугает приведённая ниже объёмная инструкция: при сформированной привычке использования Live template-ов (эта привычка сходна с повседневным применением сочетаний клавиш) скорость выполнения описанных ниже операций займёт считанные секунды.
- Скопируйте в буфер обмен имя переменной, содержащей массив, либо само
выражение массива.
Чтобы среда разработки смогла автоматически заполнить позицию
1-ого
параметра нужным значением, сформируйте привычку делать это копирование перед тем, как начинать вводить Live template функции getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne. - Начните набирать имя функции —
getArrayElementSatisfiesThePredicateIfSuchElementIsExactlyOne.
Подсветится 2 варианта автодополнения:
- Круглая иконка с буквой — это просто автодополнение имени функции, стандартная функциональность среды разработки. Нажатие на Enter введёт полное имя функции, а также при необходимости объявления импорта этой функции. Неплохо, однако это не предел, до которого можно частично автоматизировать процесс.
- Иконка с клише — это как раз нужный шаблон.
Нажмите Enter.
Произойдёт вставка шаблона кода, при этом значение
1-ого
параметра будет автоматически выделено и заполнено содержимым буфера обмена. Поскольку при следовании данному руководству менять подставленное значениеtargetArray
на другое не требуется, выйдете из режима редактирования1-ого
параметра, нажав Enter ещё раз.
- Введите имя параметра предиката — стрелочной функции. Данным параметром является элемент массива, однако рекомендуется дать ему более конкретное имя, чем «element». Когда закончите вводить, нажмите Tab. Если этому будет препятствовать на этот раз ненужное Вам автодополнение, то сначала нажмите Esc.
- Введите тип параметра предиката, затем нажмите
Enter
. - Удалите лишний код.