Вывод возвращаемого типа из универсального типа?

#typescript #typescript-generics

#typescript #typescript-дженерики

Вопрос:

Следующее работает, но .getData() имеет возвращаемый тип any , который не идеален, поскольку это вызов пользовательского интерфейса API.

На самом деле возвращаемый тип здесь не any вещь, но строго зависит от типа объекта, хранящегося в массиве items.

Могу ли я в любом случае предоставить возвращаемый тип потребителю этого метода?

 class Group<T> {
  items: Array<T> = [];

  addItem(item: T) {
      this.items.push(item);
  }

  getData(itemIndex: number) {
    // Any is T
    return (this.items[itemIndex] as any).data;
  }
}

class NumberItem {
  data: number;

  constructor(data: number) {
      this.data = data;
  }
}

class StringItem {
  data: String = "";

  constructor(data: String) {
      this.data = data;
  }
}

let n1 = new NumberItem(3);
let n2 = new NumberItem(4);

let g1 = new Group<NumberItem>();
g1.addItem(n1);
g1.addItem(n2);

console.log(g1.getData(1));
  

Ссылка на игровую площадку

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

1. Как вы ожидаете, что он сможет вывести тип из свойства, которое находится внутри универсального типа? Вы должны использовать unknown , но это примерно так же хорошо, как и получается.

2. @MikeS. Это неправильно; смотрите мой ответ.

3. @kaya3 Это не так, но я сформулировал это неправильно. Вы не можете узнать тип из свойства внутри универсального, если вы не знаете имя свойства, ваше решение работает, потому что оно полагается на data свойство, которое всегда будет там. Отличное решение, хотя не знал, что вы можете это сделать.

4. @MikeS. Этот вопрос не касается случая, когда имя свойства неизвестно, но в этом случае это все еще возможно; верхняя граница не требуется, и возвращаемый тип будет T[keyof T] .

5. Вы абсолютно правы, спасибо за разъяснение

Ответ №1:

Дайте T верхнюю границу, чтобы у нее было data свойство, тогда возвращаемый тип будет T['data'] . Таким образом, также нет необходимости в утверждении типа внутри getData метода.

 class Group<T extends { data: any }> {
  items: Array<T> = [];

  addItem(item: T) {
    this.items.push(item);
  }

  getData(itemIndex: number): T['data'] {
    return this.items[itemIndex].data;
  }
}
  

Использование:

 let n1 = new NumberItem(3);
let n2 = new NumberItem(4);

let g1 = new Group<NumberItem>();
g1.addItem(n1);
g1.addItem(n2);

// result: number
const result = g1.getData(1);
  

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

1. Я обновил свой код, все еще показывает any в качестве типа typescriptlang.org/play ? #code/…

2. @user11406 Вы не добавили аннотацию возвращаемого типа : T['data'] .

3. Супер аккуратно! Я понятия не имел, что это возможно. Спасибо.