Typescript жалуется на типы переменных после разрушения массива

#typescript

#typescript

Вопрос:

У меня есть функция

 function foo() {
    return ["", 1, () => ""];
}
  

типы: string , number и (() => string)

однако после того, как я разрушу эти значения

 const [str, num, func] = foo();
  

компилятор обрабатывает каждую переменную как тип: string | number | (() => string)

Я хочу передать эти переменные в функции, но компилятор жалуется, что типы не совпадают, и моя среда разработки сходит с ума из-за красного текста. Что я могу сделать?

Ответ №1:

Укажите тип возвращаемого значения функции

 function foo(): [string, number, () => string] {
    return ["", 1, () => ""];
}
  

Это будет строго вводить функцию для возврата массива с:

  • значение индекса 0 должно быть типом string
  • значение индекса 1 должно быть типом number
  • значение индекса 2 должно быть типом () => string / функцией, возвращающей строку
 function foo(): [string, number, () => string] {
    return [0, 1, () => ""]; // Will shows error because index 0 is number, not string
}
  

Комментарии:

1. Это было просто. Спасибо 🙂

2. Я предполагаю, что это потому, что TS выводит возвращаемый тип из массива any ? или unknown ? Как TS выводит типы в этой ситуации?

3. Когда вы возвращаете массив из функции, Typescript автоматически устанавливает возвращаемый тип как все возможные типы внутри возвращаемого массива, вот почему @MatasLiu получает string | number | (() => string) для каждого типа возвращаемого значения массива, как описано в ответе @Curtis Fenner, а не any или unknown . Если вы хотите строго ввести его как "index 0 is string, index 1 is number, index 2 is function" , вам нужно объявить возвращаемый тип, как я сделал в своем ответе.

4. Я бы предположил, что ваша альтернатива небезопасна и as является опасной операцией, было бы хорошо, если бы вы удалили альтернативу 😉

Ответ №2:

По умолчанию TypeScript определяет тип литерала массива не как кортеж, а как массив объединения всех типов элементов. Таким образом, const x = [a, b, c]; предполагается, что in не имеет типа [A, B, C] , а вместо этого (A | B | C)[] .

Если вы хотите, чтобы TypeScript определял тип кортежа, вы должны явно указать, что:

 const x: [A, B, C] = [a, b, c]; // this typechecks
  

Альтернативой является использование as const синтаксиса:

 const x = [a, b, c] as const; // infers as `readonly [A, B, C]`
  

Это не единственное место, где TypeScript выводит менее специфичный тип, чем кажется возможным. Например, строковые литералы по умолчанию выводят as string вместо их литерального типа: let x = "word"; // string vs let x = "word" as const; // "word" vs const x = "word"; // "word"

Ответ №3:

Другой способ добиться этого:

 function foo() {
  return ['', 1, () => ''] as const
}

const [str, num, func] = foo()
  

Основное различие с as const и без него заключается в том, что:

  • as const сообщает ts, что это неизменяемое значение, следовательно, ts выводит конкретный тип, который в данном случае является кортежем из 3, и, как вы знаете, кортеж может иметь разные типы
  • без этого as const ts выводит это как Array , а массив принимает параметр одного типа, но в этом случае массив содержит значения string, number и func. Следовательно, ts выводит это как (string | number | () -> string)[]

Комментарии:

1. Это определенно более элегантно!