Тьфу, я вижу, что происходит, и я думаю, что единственный разумный ответ здесь - сделать то, что ты сделал: аннотировать legs
как Leg[]
.
Итак, подпись библиотечного типа для Array
метод find()
перегружен , а перегрузка, которая принимает определяемый пользователем тип защиты обратного вызова и возвращает тип суженного элемента, равна generi c:
find<S extends T>(
predicate: (this: void, value: T, index: number, obj: T[]) => value is S, thisArg?: any
): S | undefined;
find(predicate: (value: T, index: number, obj: T[]) => unknown, thisArg?: any): T | undefined;
Если вы не аннотируете legs
, он получает тип объединения Array<Leg> | Array<LegA>
. Этот тип считается совместимым с Array<Leg>
, но он не будет обрабатывать его как таковой автоматически (что, вероятно, хорошо. Array<LegA>
не должен позволять вам push()
a LegB
на него, но Array<Leg>
должен) ,
Это означает, что тип legs.find
сам по себе является объединением функций, подписи которых не идентичны:
type LegsFind = {
<S extends LegA>(p: (this: void, v: LegA, i: number, o: LegA[]) => v is S, t?: any): S | undefined;
(p: (v: LegA, i: number, o: LegA[]) => unknown, t?: any): LegA | undefined;
} | {
<S extends Leg>(p: (this: void, v: Leg, i: number, o: Leg[]) => v is S, t?: any): S | undefined;
(p: (v: Leg, i: number, o: Leg[]) => unknown, t?: any): Leg | undefined;
};
До TypeScript 3.3 компилятор просто сдаться и сказать вам, что он не знает, как вызвать объединение таких функций. И кто-то скажет вам изменить Array<X> | Array<Y>
на Array<X | Y>
, если вы вызываете немутантные методы, такие как find()
, и вы будете использовать Leg[]
и двигаться дальше.
TypeScript 3.3 введено улучшено поведение для вызова типов объединения . Есть случаи, когда компилятор может взять объединение функций и представить его как одну функцию, которая принимает пересечение параметров от каждого члена объединения. Вы можете прочитать больше об этом в соответствующем запросе на извлечение, microsoft / TypeScript # 29011 .
Но, бывают случаи, когда он не может сделать это : конкретно если несколько ветвей объединения перегружены или генерируют c функции. К сожалению для find()
, это тот случай, когда вы находитесь. Похоже, что компилятор пытается найти способ сделать это вызываемым, но он отказывается от общих c подписей, соответствующих пользователю -defined-type-guard сужается и заканчивается только «обычным», вероятно потому, что они совместимы друг с другом:
type LegsFind33 = (p: (v: LegA, i: number, o: Leg[]) => unknown, thisArg?: any) => Leg | undefined;
Так что вы называете это успешно, сужения не происходит, и вы запускаете в проблему здесь. Проблема вызова союзов функций не полностью решена; его проблема GitHub microsoft / TypeScript # 7294 закрыта и помечена как «Revisit».
Таким образом, пока этот вопрос не будет вновь рассмотрен, советуем все же обрабатывать Array<X> | Array<Y>
как Array<X | Y>
, если вы вызываете немутирующие методы, такие как find()
... use Leg[]
и двигаться дальше.
Хорошо, надеюсь, это поможет; удачи!