Version de TypeScript: 2.0.8
Code
// 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)) {
}
}
}
}
Compilé avec cmd: tsc --noImplicitAny test.ts
Comportement prévisible:
Aucune erreur
Comportement réel:
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.
Il s'agit d'un problème d'analyse de flux de contrôle. Afin de déduire un type pour ITEM
nous devons déterminer le type de flux de contrôle de arg.arr
. Cela signifie à son tour que nous devons examiner les constructions qui affectent le type de arg
. Cela inclut l'appel à otherFunc
qui semble être un prédicat de type défini par l'utilisateur. Afin de déterminer s'il _est_ un prédicat de type, nous résolvons l'expression d'appel, ce qui implique la résolution des expressions d'argument, ce qui nous oblige à connaître le type de ITEM
. Cela crée une circularité que nous ne pouvons pas résoudre, nous revenons donc à un type implicite any
.
Nous pouvons résoudre ce problème en demandant à la logique de reconnaissance de prédicat de type de résoudre d'abord le type de l'objet fonction et d'examiner toutes les signatures d'appel. Si aucun d'entre eux n'est un prédicat de type défini par l'utilisateur, nous pouvons renflouer tôt sans résoudre les expressions d'argument d'appel, ce qui évite la circularité.
Pendant ce temps, vous pouvez briser la circularité simplement en ajoutant des parenthèses à arg
dans l'appel à otherFunc
. En d'autres termes, changez l'appel en otherFunc(ITEM, (arg))
. Cela fait que l'analyseur de flux de contrôle ne considère plus l'appel comme un possible appel de prédicat de type défini par l'utilisateur.
@ahejlsberg
Merci pour la solution de contournement entre parenthèses.
Je veux comprendre cela. Les relations publiques sont acceptables, n'est-ce pas?
@arusakov Fix maintenant dans Master!
Commentaire le plus utile
Il s'agit d'un problème d'analyse de flux de contrôle. Afin de déduire un type pour
ITEM
nous devons déterminer le type de flux de contrôle dearg.arr
. Cela signifie à son tour que nous devons examiner les constructions qui affectent le type dearg
. Cela inclut l'appel àotherFunc
qui semble être un prédicat de type défini par l'utilisateur. Afin de déterminer s'il _est_ un prédicat de type, nous résolvons l'expression d'appel, ce qui implique la résolution des expressions d'argument, ce qui nous oblige à connaître le type deITEM
. Cela crée une circularité que nous ne pouvons pas résoudre, nous revenons donc à un type impliciteany
.Nous pouvons résoudre ce problème en demandant à la logique de reconnaissance de prédicat de type de résoudre d'abord le type de l'objet fonction et d'examiner toutes les signatures d'appel. Si aucun d'entre eux n'est un prédicat de type défini par l'utilisateur, nous pouvons renflouer tôt sans résoudre les expressions d'argument d'appel, ce qui évite la circularité.
Pendant ce temps, vous pouvez briser la circularité simplement en ajoutant des parenthèses à
arg
dans l'appel àotherFunc
. En d'autres termes, changez l'appel enotherFunc(ITEM, (arg))
. Cela fait que l'analyseur de flux de contrôle ne considère plus l'appel comme un possible appel de prédicat de type défini par l'utilisateur.