Тогда массив может быть пустым или содержать n элементов.

Обычной задачей является проверка того, пуст ли массив для работы с ним. Как определить, что массив пуст?

В Javascript эта задача выполняется с помощью условного блока и проверки свойства .length массива.

Но можно ли использовать язык ввода Typescript, чтобы массив не был пустым без использования условного оператора?

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

Что вы сделаете, так это создадите новый тип, похожий на Array, который позволит вам определить массив, который не может быть пустым по определению.

Назовем этот тип NonEmptyArray.

type NonEmptyArray<T> = [T, ...T[]]

const emptyArr: NonEmptyArray<Item> = [] // error ❌

const emptyArr2: Array<Item> = [] // ok ✅ 

function expectNonEmptyArray(arr: NonEmptyArray<unknown>) {
    console.log('non empty array', arr)
}

expectNonEmptyArray([]) // you cannot pass an empty array. ❌

expectNonEmptyArray(['som valuue']) // ok ✅

So whenever you require, for example, a function parameter to be an array that cannot be empty, you can use NonEmptyArray .

Единственным недостатком является то, что теперь вам потребуется функция «защиты типов», поскольку простая проверка того, что свойство length массива не равно 0, не преобразует его в тип NonEmptyArray.

function getArr(arr: NonEmptyArray<string>) {
  return arr;
}

const arr3 = ['1']
if (arr3.length > 0)) {
  // ⛔️ Error: Argument of type 'string[]' is not
  // assignable to parameter of type 'NonEmptyArr<string>'.
  getArr(arr3);
}

Эта ошибка возникает из-за того, что getArr ожидает, что аргумент будет NonEmptyArray, но arr3 имеет тип Array.

Тип охранников

Функция «защиты типа» позволяет вам «помочь» Typescript правильно определить тип некоторой переменной.

Это простая функция, которая возвращает логическое значение. Если это значение равно true, то Typescript будет считать, что оцениваемая переменная относится к тому или иному типу.

// Type Guard
function isNonEmpty<A>(arr: Array<A>): arr is NonEmptyArray<A>{
    return arr.length > 0
}

Эта функция получает общий массив (отсюда и использование A) и проверяет, больше ли свойство length, чем 0.

Эта функция помечена как возвращающая arr is NonEmptyArray<A>, т. е. значение оцениваемого условия равно true. Typescript поймет, что используемый параметр arr имеет тип NonEmptyArray.

// Type Guard
function isNonEmpty<A>(arr: Array<A>): arr is NonEmptyArray<A>{
    return arr.length > 0
}

function getArr(arr: NonEmptyArray<string>) {
  return arr;
}

const arr3 = ['1']
//     ^?   const arr3: string[]
if (isNonEmpty(arr3)) {
  getArr(arr3);
//        ^? const arr3: NonEmptyArray<string>
}

Простой способ понять защиту типа состоит в том, что вы «приводите» один тип к другому типу тогда и только тогда, когда выполняется определенное условие. Что делает это преобразование безопасным по сравнению с простым приведением типов as NonEmptyArray

Ознакомьтесь с игровой площадкой машинописи с этими примерами.