аргумент функции typescript наследуется от

#typescript #generics

Вопрос:

У меня есть супер класс, такой как

 class SuperClassy {
}
 

В котором есть много других классов, расширяющих его:

 class SubClassy extends SuperClassy {
}

class OtherSubClass extends SuperClassy {
}
 

и т.д.

У меня есть функции, для которых я хочу указать, что аргумент должен находиться в этой группе производных классов.

Я не хочу создавать тип объединения вручную, я бы предпочел просто объявить, что рассматриваемый аргумент должен наследоваться от СуперКласса.

Что-то вроде:

 function doStuff(c: InheritsFrom<SuperClassy>) {
}
 

таким образом, что это скомпилирует:

 doStuff(new SubClassy()) {
}
 

и этого не будет:

 doStuff(4);
 

— РЕДАКТИРОВАТЬ —

Вот пример, когда простое требование, чтобы параметр был суперклассным, не работает:

 
class SuperClassy {
  id: string;
}

class SubClassy extends SuperClassy {
  x: number;
}

class OtherSubClass extends SuperClassy {
  y: number;
}

function doStuff(c: (c: SuperClassy) => (d: SuperClassy) => boolean) {
  return 'j';
}

doStuff((c: SubClassy) => {
  return (k: OtherSubClass) => {
    return c.id === k.id;
  }
});
 

Компилятор выдает эту ошибку:

 Argument of type '(c: SubClassy) => (k: OtherSubClass) => boolean' is not assignable to parameter of type '(c: SuperClassy) => (d: SuperClassy) => boolean'.
  Types of parameters 'c' and 'c' are incompatible.
    Property 'x' is missing in type 'SuperClassy' but required in type 'SubClassy'.
 

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

1. Разве ты не можешь просто сделать function doStuff(c: SuperClassy) это ?

2. Смотрите обновленный вопрос для случая использования, когда это нарушается

3. Тип функции сложнее, чем вы думали. Они контравариантны в своих типах аргументов и ковариантны в своем типе возвращаемых значений. Тебе нужно переосмыслить их. В принципе, функция, в которую вы передали, doStuff не является подтипом типа параметра, для которого определен doStuff . т. е. (c: SubClassy) => ... не является подтипом (c: SuperClassy) => ... , на самом деле все наоборот.

Ответ №1:

Как насчет использования дженериков? (Я добавил значения по умолчанию в определения классов, чтобы подавить ошибки компилятора.

 class SuperClassy {
  id: string = "id";
}

class SubClassy extends SuperClassy {
  x: number = 0;
}

class OtherSubClass extends SuperClassy {
  y: number = 0;
}

function doStuff<T extends SuperClassy, U extends SuperClassy>(
  c: (c: T) => (d: U) => boolean
) {
  return "j";
}

doStuff((c: SubClassy) => {
  return (k: OtherSubClass) => {
    return c.id === k.id;
  };
});