Voici les erreurs de métadonnées que vous pouvez rencontrer, avec des explications et des corrections suggérées.
Forme d'expression non prise en charge
Utile : Le compilateur a rencontré une expression qu'il n'a pas comprise lors de l'évaluation des métadonnées Angular.
Les fonctionnalités du langage en dehors de la syntaxe d'expression restreinte du compilateur peuvent produire cette erreur, comme le montre l'exemple suivant :
// ERROR
export class Fooish { … }
…
const prop = typeof Fooish; // typeof is not valid in metadata
…
// bracket notation is not valid in metadata
{ provide: 'token', useValue: { [prop]: 'value' } };
…
Vous pouvez utiliser typeof et la notation entre crochets dans le code applicatif normal.
Vous ne pouvez simplement pas utiliser ces fonctionnalités dans les expressions qui définissent des métadonnées Angular.
Évitez cette erreur en vous en tenant à la syntaxe d'expression restreinte du compilateur lorsque vous écrivez des métadonnées Angular, et méfiez-vous des fonctionnalités TypeScript nouvelles ou inhabituelles.
Référence à un symbole local (non exporté)
Utile : Reference to a local (non-exported) symbol 'symbol name'. Consider exporting the symbol.
Le compilateur a rencontré une référence à un symbole défini localement qui n'était soit pas exporté, soit pas initialisé.
Voici un exemple du problème avec un provider.
// ERROR
let foo: number; // neither exported nor initialized
@Component({
selector: 'my-component',
template: … ,
providers: [
{ provide: Foo, useValue: foo }
]
})
export class MyComponent {}
Le compilateur génère la fabrique du composant, qui inclut le code du provider useValue, dans un module séparé. Ce module de fabrique ne peut pas remonter jusqu'à ce module source pour accéder à la variable locale (non exportée) foo.
Vous pouvez corriger le problème en initialisant foo.
let foo = 42; // initialized
Le compilateur va replier l'expression dans le provider comme si vous aviez écrit ceci.
providers: [{provide: Foo, useValue: 42}];
Vous pouvez aussi le corriger en exportant foo, en partant du principe que foo sera assigné à l'exécution, lorsque vous connaîtrez réellement sa valeur.
// CORRECTED
export let foo: number; // exported
@Component({
selector: 'my-component',
template: … ,
providers: [
{ provide: Foo, useValue: foo }
]
})
export class MyComponent {}
Ajouter export fonctionne souvent pour les variables référencées dans des métadonnées comme providers et animations, car le compilateur peut générer des références aux variables exportées dans ces expressions. Il n'a pas besoin des valeurs de ces variables.
Ajouter export ne fonctionne pas lorsque le compilateur a besoin de la valeur réelle
pour générer du code.
Par exemple, cela ne fonctionne pas pour la propriété template.
// ERROR
export let someTemplate: string; // exported but not initialized
@Component({
selector: 'my-component',
template: someTemplate,
})
export class MyComponent {}
Le compilateur a besoin de la valeur de la propriété template immédiatement pour générer la fabrique du composant.
La seule référence à la variable ne suffit pas.
Préfixer la déclaration par export ne fait que produire une nouvelle erreur, « Only initialized variables and constants can be referenced ».
Seules les variables et constantes initialisées
Utile : Only initialized variables and constants can be referenced because the value of this variable is needed by the template compiler.
Le compilateur a trouvé une référence à une variable exportée ou à un champ statique qui n'était pas initialisé. Il a besoin de la valeur de cette variable pour générer du code.
L'exemple suivant tente de définir la propriété template du composant avec la valeur de la variable exportée someTemplate, qui est déclarée mais non assignée.
// ERROR
export let someTemplate: string;
@Component({
selector: 'my-component',
template: someTemplate,
})
export class MyComponent {}
Vous obtiendriez aussi cette erreur si vous importiez someTemplate depuis un autre module en oubliant de l'y initialiser.
import {Component} from '@angular/core';
// ERROR - not initialized there either
import {someTemplate} from './config';
@Component({
selector: 'my-component',
template: someTemplate,
})
export class MyComponent {}
Le compilateur ne peut pas attendre l'exécution pour obtenir les informations du template.
Il doit déduire statiquement la valeur de la variable someTemplate à partir du code source afin de pouvoir générer la fabrique du composant, qui contient les instructions pour construire l'élément à partir du template.
Pour corriger cette erreur, fournissez la valeur initiale de la variable dans une clause d'initialisation sur la même ligne.
// CORRECTED
export let someTemplate = '<h1>Greetings from Angular</h1>';
@Component({
selector: 'my-component',
template: someTemplate,
})
export class MyComponent {}
Référence à une classe non exportée
Utile : Reference to a non-exported class <class name>.
Consider exporting the class.
Des métadonnées ont référencé une classe qui n'était pas exportée.
Par exemple, vous avez peut-être défini une classe et l'avez utilisée comme jeton d'injection dans un tableau de providers, en oubliant d'exporter cette classe.
// ERROR
abstract class MyStrategy { }
…
providers: [
{ provide: MyStrategy, useValue: … }
]
…
Angular génère une fabrique de classe dans un module séparé, et cette fabrique ne peut accéder qu'aux classes exportées. Pour corriger cette erreur, exportez la classe référencée.
// CORRECTED
export abstract class MyStrategy { }
…
providers: [
{ provide: MyStrategy, useValue: … }
]
…
Variable ou constante déstructurée non prise en charge
Utile : Referencing an exported destructured variable or constant is not supported by the template compiler. Consider simplifying this to avoid destructuring.
Le compilateur ne prend pas en charge les références à des variables assignées par déstructuration.
Par exemple, vous ne pouvez pas écrire quelque chose comme ceci :
// ERROR
import { configuration } from './configuration';
// destructured assignment to foo and bar
const {foo, bar} = configuration;
…
providers: [
{provide: Foo, useValue: foo},
{provide: Bar, useValue: bar},
]
…
Pour corriger cette erreur, faites référence à des valeurs non déstructurées.
// CORRECTED
import { configuration } from './configuration';
…
providers: [
{provide: Foo, useValue: configuration.foo},
{provide: Bar, useValue: configuration.bar},
]
…
Impossible de résoudre le type
Utile : Le compilateur a rencontré un type et ne parvient pas à déterminer quel module exporte ce type.
Cela peut arriver si vous faites référence à un type ambiant.
Par exemple, le type Window est un type ambiant déclaré dans le fichier global .d.ts.
Vous obtiendrez une erreur si vous le référencez dans le constructeur du composant, que le compilateur doit analyser statiquement.
// ERROR
@Component({ })
export class MyComponent {
constructor (private win: Window) { … }
}
TypeScript comprend les types ambiants, vous ne les importez donc pas. Le compilateur Angular ne comprend pas un type que vous omettez d'exporter ou d'importer.
Dans ce cas, le compilateur ne sait pas comment injecter quelque chose avec le jeton Window.
Ne faites pas référence à des types ambiants dans les expressions de métadonnées.
Si vous devez injecter une instance d'un type ambiant, vous pouvez contourner le problème en quatre étapes :
- Créez un jeton d'injection pour une instance du type ambiant.
- Créez une fonction de fabrique qui renvoie cette instance.
- Ajoutez un provider
useFactoryavec cette fonction de fabrique. - Utilisez
@Injectpour injecter l'instance.
Voici un exemple illustratif.
// CORRECTED
import {Inject, InjectionToken, Component} from '@angular/core';
export const WINDOW = new InjectionToken('Window');
export function _window() { return window; }
@Component({
…
providers: [
{ provide: WINDOW, useFactory: _window }
]
})
export class MyComponent {
constructor (@Inject(WINDOW) private win: Window) { … }
}
Le type Window dans le constructeur ne pose plus de problème au compilateur, car celui-ci
utilise @Inject(WINDOW) pour générer le code d'injection.
Angular fait quelque chose de similaire avec le jeton DOCUMENT, ce qui vous permet d'injecter l'objet document du navigateur (ou une abstraction de celui-ci, selon la plateforme sur laquelle l'application s'exécute).
import {Inject, Component} from '@angular/core';
import { DOCUMENT } from '@angular/common';
@Component({ … })
export class MyComponent {
constructor (@Inject(DOCUMENT) private doc: Document) { … }
}
Nom attendu
Utile : Le compilateur attendait un nom dans une expression qu'il évaluait.
Cela peut arriver si vous utilisez un nombre comme nom de propriété, comme dans l'exemple suivant.
// ERROR
provider: [{provide: Foo, useValue: {0: 'test'}}];
Changez le nom de la propriété pour une valeur non numérique.
// CORRECTED
provider: [{provide: Foo, useValue: {'0': 'test'}}];
Nom de membre d'enum non pris en charge
Utile : Angular n'a pas pu déterminer la valeur du membre d'enum que vous avez référencé dans les métadonnées.
Le compilateur comprend les valeurs d'enum simples, mais pas les valeurs complexes comme celles dérivées de propriétés calculées.
// ERROR
enum Colors {
Red = 1,
White,
Blue = "Blue".length // computed
}
…
providers: [
{ provide: BaseColor, useValue: Colors.White } // ok
{ provide: DangerColor, useValue: Colors.Red } // ok
{ provide: StrongColor, useValue: Colors.Blue } // bad
]
…
Évitez de faire référence à des enums dotés d'initialiseurs complexes ou de propriétés calculées.
Les expressions de template étiquetées ne sont pas prises en charge
Utile : Tagged template expressions are not supported in metadata.
Le compilateur a rencontré une expression de template étiquetée JavaScript ES2015, comme la suivante.
// ERROR
const expression = 'funky';
const raw = String.raw`A tagged template ${expression} string`;
…
template: '<div>' + raw + '</div>'
…
String.raw() est une fonction d'étiquetage native de JavaScript ES2015.
Le compilateur AOT ne prend pas en charge les expressions de template étiquetées ; évitez-les dans les expressions de métadonnées.
Référence à un symbole attendue
Utile : Le compilateur attendait une référence à un symbole à l'emplacement indiqué dans le message d'erreur.
Cette erreur peut se produire si vous utilisez une expression dans la clause extends d'une classe.