Введите защитный доступ к индексируемому свойству — Typescript

#typescript

#typescript

Вопрос:

Ошибка связана с сообщением, что левая / правая часть арифметической операции должна иметь тип ‘number’, ‘bigint’ и т. Д….

   sort({ key, direction }: SortOptions<Listing>) {
    this.dataSet.sort((a, b) => { // <--- dataSet: Listing[]
      let returnVal;
      if (typeof a[key] === 'number' amp;amp; typeof b[key] === 'number')
        returnVal = a[key] - b[key]; // <-- error here
      ...
      return direction === 'asc' ? returnVal : -returnVal;
      });
  }
  

для ключа уже проверен тип a keyof T , где a и b имеют тип T.

 interface SortOptions<T> {
  key: keyof T;
  direction: 'asc' | 'desc';
}

export interface Listing {
  id: number;
  title: string;
  condition: string;
  description: string;
  price: number;
  stock: number;
  sold: boolean;
  display: boolean;
}
  

Если я удалю проверку типа по ключу, т.е. SortOptions<Listing> Ошибка не отображается. Но это потому, что тогда нет безопасности типов как key есть any , а a[key] также any

Я знаю, что есть простые способы javascript, подобные a[key] этой работе. Но я пытаюсь правильно проверить тип.

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

1. Вероятно, потому, что typeof NaN также является «числом» :).

2. Вы можете извлечь a[key] и b[key] к переменным, тогда typeguard будет работать

3. @AlekseyL. у меня было ощущение, что это может быть ограничением компилятора. Знаете ли вы, почему? Кроме того, спасибо, не стесняйтесь оставлять ответ, я проголосую за него.

4. @AlekseyL. просто дикое предположение: геттеры в JS могут изменять значения, поэтому после запуска typeof a[key] === 'number' нет гарантии a[key] , что они вернут то же значение в следующем операторе.

5. @zerkms конечно, я понимаю, что ты говоришь. Я просто думаю, что это не связано с тем, почему a[key] === 'number' не работает. Если бы это было так — мой пример также не должен работать.

Ответ №1:

Известная проблема заключается в том, что TypeScript не во всех случаях выполняет сужение анализа потока управления при проверке свойств объекта. Некоторые отсутствующие в настоящее время варианты использования: проверка свойств на подписи индексов в квадратных скобках; проверка свойств на значения универсальных типов. Недавно были рассмотрены некоторые такие случаи, но, похоже, все еще существует пробел, если вы используете индексированный доступ к нелитеральному ключу. (Не уверен, к какой существующей проблеме, если таковая имеется, это относится). Я не уверен, что этот конкретный вариант использования когда-либо будет разрешен, поскольку предыдущие исправления приводили к снижению производительности.

В любом случае такое сужение защиты типа лучше работает с переменными, чем с выражениями переменных (например, с доступом к свойствам), поэтому, если вы сомневаетесь, разумным обходным путем является присвоение выражения, о котором вы заботитесь, его собственной переменной:

 sort({ key, direction }: SortOptions<Listing>) {
    this.dataSet.sort((a, b) => { // <--- dataSet: Listing[]
        let returnVal;
        const aKey = a[key]; // assign to new variable
        const bKey = b[key]; // assign to new variable
        if (typeof aKey === 'number' amp;amp; typeof bKey === 'number') // check variables
            returnVal = aKey - bKey; // no error now
        ...    
        return direction === 'asc' ? returnVal : -returnVal;
    });
}
  

Это должно работать так, как вы ожидаете. Надеюсь, это поможет; удачи!

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

1. На самом деле это так , но не в этом конкретном случае

2. Да, спасибо. Литеральные ключи проверяются даже с помощью доступа к скобкам; Я отредактировал свой ответ, чтобы указать доступ к свойству для нелитерального индекса.

3. Спасибо, имеет смысл. Но теперь связанная проблема, похоже, не связана (и исправлена)

4. Хм, я думаю, что связанная проблема была связана, но они исправили только ее часть (или, по крайней мере, есть связанные проблемы, закрытые как дубликаты). Я спрошу, достаточно ли близки Microsoft / TypeScript # 28081 или Microsoft / TypeScript # 4742 или это отдельная проблема.

5. Это также может быть Microsoft / TypeScript #22214