Версия TypeScript: 2.0.8
Код
// test.ts
interface Type {
type: number;
}
interface TypeExt extends Type {
arr: Type[];
}
const guard = (arg: Type): arg is TypeExt => arg.type === 1;
const otherFunc = (arg1: Type, arg2: TypeExt): void => {};
export function y(arg: Type): void {
if (guard(arg)) {
for (const ITEM/* error is here */ of arg.arr) {
if (otherFunc(ITEM, arg)) {
}
}
}
}
Скомпилировано с помощью cmd: tsc --noImplicitAny test.ts
Ожидаемое поведение:
Нет ошибок
Фактическое поведение:
test.ts(14,16): error TS7022: 'ITEM' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer.
Это проблема анализа потока управления. Чтобы определить тип для ITEM
нам нужно выяснить тип потока управления arg.arr
. Это, в свою очередь, означает, что нам нужно рассмотреть конструкции, которые влияют на тип arg
. Это включает в себя вызов otherFunc
который выглядит так, как будто _ может_ быть предикатом определенного пользователем типа. Чтобы определить, является ли он _ предикатом типа, мы разрешаем выражение вызова, что влечет за собой разрешение выражений аргументов, что требует от нас знания типа ITEM
. Это создает замкнутость, которую мы не можем разрешить, поэтому мы возвращаемся к неявному типу any
.
Мы можем исправить это, если сначала логика распознавания предикатов типа определит тип функционального объекта и проверит все сигнатуры вызовов. Если ни один из них не является предикатом типа, определяемым пользователем, мы можем выручить раньше, не разрешая выражения аргументов вызова, что позволяет избежать цикличности.
Между тем, вы можете нарушить цикличность, просто добавив круглые скобки к arg
в вызове otherFunc
. Другими словами, измените вызов на otherFunc(ITEM, (arg))
. Это заставляет анализатор потока управления больше не рассматривать вызов как возможный вызов предиката определенного пользователем типа.
@ahejlsberg
Спасибо за обходные скобки.
Я хочу в этом разобраться. PR - это приемлемо, не правда ли?
@arusakov Исправь сейчас в мастере!
Самый полезный комментарий
Это проблема анализа потока управления. Чтобы определить тип для
ITEM
нам нужно выяснить тип потока управленияarg.arr
. Это, в свою очередь, означает, что нам нужно рассмотреть конструкции, которые влияют на типarg
. Это включает в себя вызовotherFunc
который выглядит так, как будто _ может_ быть предикатом определенного пользователем типа. Чтобы определить, является ли он _ предикатом типа, мы разрешаем выражение вызова, что влечет за собой разрешение выражений аргументов, что требует от нас знания типаITEM
. Это создает замкнутость, которую мы не можем разрешить, поэтому мы возвращаемся к неявному типуany
.Мы можем исправить это, если сначала логика распознавания предикатов типа определит тип функционального объекта и проверит все сигнатуры вызовов. Если ни один из них не является предикатом типа, определяемым пользователем, мы можем выручить раньше, не разрешая выражения аргументов вызова, что позволяет избежать цикличности.
Между тем, вы можете нарушить цикличность, просто добавив круглые скобки к
arg
в вызовеotherFunc
. Другими словами, измените вызов наotherFunc(ITEM, (arg))
. Это заставляет анализатор потока управления больше не рассматривать вызов как возможный вызов предиката определенного пользователем типа.