填寫這份《一分鐘調查》,幫我們(開發組)做得更好!去填寫Home

AOT 元資料錯誤

AOT metadata errors

你可能遇到一些元資料錯誤,下面是對它們的解釋和糾正建議。

不支援此表示式格式Expression form not supported
參考了局部(未匯出的)符號Reference to a local (non-exported) symbol
只允許初始化過的變數和常量Only initialized variables and constants
參考了未匯出的類別Reference to a non-exported class
參考了未匯出的函式Reference to a non-exported function
不支援函式呼叫Function calls are not supported
不支援解構變數或常量Destructured variable or constant not supported
不能解析此型別Could not resolve type
期待是名字Name expected
不支援的列舉成員名Unsupported enum member name
不支援帶標籤函式的範本表示式Tagged template expressions are not supported
期待是符號參考Symbol reference expected

The following are metadata errors you may encounter, with explanations and suggested corrections.

不支援表達形式 (Expression form not supported)

Expression form not supported

編譯器在對 Angular 元資料求值時遇到了一個它不能理解的表示式。

The compiler encountered an expression it didn't understand while evaluating Angular metadata.

如以下範例所示,使用了編譯器的受限表示式語法之外的語言特性可能會產生此錯誤:

Language features outside of the compiler's restricted expression syntax can produce this error, as seen in the following example:

      
      // 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' } };
  ...
    

你可以在普通的應用程式碼中使用 typeof 和方括號標記法來指定屬性名,但是這些特性不能在定義 Angular 元資料的表示式中使用。

You can use typeof and bracket notation in normal application code. You just can't use those features within expressions that define Angular metadata.

透過在編寫 Angular 元資料時堅持使用編譯器的受限表示式語法來避免此錯誤,並小心新的或不常用的 TypeScript 功能。

Avoid this error by sticking to the compiler's restricted expression syntax when writing Angular metadata and be wary of new or unusual TypeScript features.

參考本地(未匯出的)符號 (Reference to a local (non-exported) symbol)

Reference to a local (non-exported) symbol

如果要參考區域性(未匯出的)符號 'symbol name',請考慮匯出它。

Reference to a local (non-exported) symbol 'symbol name'. Consider exporting the symbol.

編譯器遇到了區域性定義的未匯出或未初始化的符號。

The compiler encountered a referenced to a locally defined symbol that either wasn't exported or wasn't initialized.

下面就是存在該問題的 provider 範例。

Here's a provider example of the problem.

      
      // ERROR
let foo: number; // neither exported nor initialized

@Component({
  selector: 'my-component',
  template: ... ,
  providers: [
    { provide: Foo, useValue: foo }
  ]
})
export class MyComponent {}
    

編譯器會在單獨的模組中產生這個 userValue 提供者的程式碼。那個工廠模組不能訪問這個原始碼模組,無法訪問這個(未匯出的)foo 變數。

The compiler generates the component factory, which includes the useValue provider code, in a separate module. That factory module can't reach back to this source module to access the local (non-exported) foo variable.

你可以透過初始化 foo 來修正這個錯誤。

You could fix the problem by initializing foo.

      
      let foo = 42; // initialized
    

編譯器會將表示式摺疊到提供者中,就像你自己寫的一樣。

The compiler will fold the expression into the provider as if you had written this.

      
      providers: [
  { provide: Foo, useValue: 42 }
]
    

另外,你也可以透過匯出 foo 來解決它,這樣 foo 將會在執行期間你真正知道它的值的時候被賦值。

Alternatively, you can fix it by exporting foo with the expectation that foo will be assigned at runtime when you actually know its value.

      
      // CORRECTED
export let foo: number; // exported

@Component({
  selector: 'my-component',
  template: ... ,
  providers: [
    { provide: Foo, useValue: foo }
  ]
})
export class MyComponent {}
    

新增 export 的方式通常用於需要在元資料中參考變數時,如 providersanimations,這樣編譯器就可以在這些表示式中產生對已匯出變數的參考了。它不需要知道這些變數的

Adding export often works for variables referenced in metadata such as providers and animations because the compiler can generate references to the exported variables in these expressions. It doesn't need the values of those variables.

當編譯器需要知道真正的值以產生程式碼時,新增 export 的方式就是無效的。比如這裡的 template 屬性。

Adding export doesn't work when the compiler needs the actual value in order to generate code. For example, it doesn't work for the template property.

      
      // ERROR
export let someTemplate: string; // exported but not initialized

@Component({
  selector: 'my-component',
  template: someTemplate
})
export class MyComponent {}
    

編譯器現在就需要 template 屬性的值來產生元件工廠。 僅僅有對該變數的參考是不夠的。 給這個宣告加上 export 字首只會產生一個新的錯誤 "Only initialized variables and constants can be referenced【只能參考初始化過的變數和常量】"。

The compiler needs the value of the template property right now to generate the component factory. The variable reference alone is insufficient. Prefixing the declaration with export merely produces a new error, "Only initialized variables and constants can be referenced".

只支援初始化過的變數和常量 (Only initialized variables and constants)

Only initialized variables and constants

只能參考已初始化過的變數和常量,因為範本編譯器需要該變數的值。

Only initialized variables and constants can be referenced because the value of this variable is needed by the template compiler.

編譯器發現某個到已匯出的變數或靜態欄位的參考是沒有初始化過的。而它需要根據那個變數的值來產生程式碼。

The compiler found a reference to an exported variable or static field that wasn't initialized. It needs the value of that variable to generate code.

下面的例子試圖把元件的 template 屬性設定為已匯出的 someTemplate 變數的值,而這個值雖然宣告過,卻沒有初始化過。

The following example tries to set the component's template property to the value of the exported someTemplate variable which is declared but unassigned.

      
      // ERROR
export let someTemplate: string;

@Component({
  selector: 'my-component',
  template: someTemplate
})
export class MyComponent {}
    

如果你從其它模組中匯入了 someTemplate,但那個模組中忘了初始化它,就會看到這個錯誤。

You'd also get this error if you imported someTemplate from some other module and neglected to initialize it there.

      
      // ERROR - not initialized there either
import { someTemplate } from './config';

@Component({
  selector: 'my-component',
  template: someTemplate
})
export class MyComponent {}
    

編譯器不能等到執行時才得到該範本的資訊。 它必須從原始碼中靜態獲得這個 someTemplate 變數的值,以便產生元件工廠,元件工廠中需要包含根據這個範本來產生元素的程式碼。

The compiler cannot wait until runtime to get the template information. It must statically derive the value of the someTemplate variable from the source code so that it can generate the component factory, which includes instructions for building the element based on the template.

要糾正這個錯誤,請在同一行的初始化子句中初始化這個變數的值。

To correct this error, provide the initial value of the variable in an initializer clause on the same line.

      
      // CORRECTED
export let someTemplate = '<h1>Greetings from Angular</h1>';

@Component({
  selector: 'my-component',
  template: someTemplate
})
export class MyComponent {}
    

參考未匯出過的類別 (Reference to a non-exported class)

Reference to a non-exported class

如果要參考未匯出的類別,請考慮匯出它。

Reference to a non-exported class. Consider exporting the class.

元資料參考了一個未匯出的類別。

Metadata referenced a class that wasn't exported.

比如,你可能定義了一個類別並在某個 providers 陣列中把它用作了依賴注入令牌,但是忘了匯出這個類別。

For example, you may have defined a class and used it as an injection token in a providers array but neglected to export that class.

      
      // ERROR
abstract class MyStrategy { }

  ...
  providers: [
    { provide: MyStrategy, useValue: ... }
  ]
  ...
    

Angular 在單獨的模組中產生類別工廠,並且該工廠只能訪問匯出的類別。要更正此錯誤,請匯出所參考的類別。

Angular generates a class factory in a separate module and that factory can only access exported classes. To correct this error, export the referenced class.

      
      // CORRECTED
export abstract class MyStrategy { }

  ...
  providers: [
    { provide: MyStrategy, useValue: ... }
  ]
  ...
    

參考未匯出過的函式 (Reference to a non-exported function)

Reference to a non-exported function

元資料中參考了未匯出的函式。

Metadata referenced a function that wasn't exported.

比如,你可能已經把某個服務提供者的 useFactory 屬性設定成了一個區域性定義但忘了匯出的函式。

For example, you may have set a providers useFactory property to a locally defined function that you neglected to export.

      
      // ERROR
function myStrategy() { ... }

  ...
  providers: [
    { provide: MyStrategy, useFactory: myStrategy }
  ]
  ...
    

Angular 在單獨的模組中產生類別工廠,該工廠只能訪問匯出的函式。要更正此錯誤,請匯出此函式。

Angular generates a class factory in a separate module and that factory can only access exported functions. To correct this error, export the function.

      
      // CORRECTED
export function myStrategy() { ... }

  ...
  providers: [
    { provide: MyStrategy, useFactory: myStrategy }
  ]
  ...
    

不支援函式呼叫 (Function calls are not supported)

Function calls are not supported

不支援函式呼叫。考慮把這個函式或 lambda 表示式替換成一個對已匯出函式的參考。

Function calls are not supported. Consider replacing the function or lambda with a reference to an exported function.

編譯器當前不支援函式表示式或 lambda 函式。例如,你不能將提供者的 useFactory 設定為這樣的匿名函式或箭頭函式。

The compiler does not currently support function expressions or lambda functions. For example, you cannot set a provider's useFactory to an anonymous function or arrow function like this.

      
      // ERROR
  ...
  providers: [
    { provide: MyStrategy, useFactory: function() { ... } },
    { provide: OtherStrategy, useFactory: () => { ... } }
  ]
  ...
    

如果你在某個提供者的 useValue 中呼叫函式或方法,也會導致這個錯誤。

You also get this error if you call a function or method in a provider's useValue.

      
      // ERROR
import { calculateValue } from './utilities';

  ...
  providers: [
    { provide: SomeValue, useValue: calculateValue() }
  ]
  ...
    

要改正這個問題,就要從模組中匯出這個函式,並改成在服務提供者的 useFactory 中參考該函式。

To correct this error, export a function from the module and refer to the function in a useFactory provider instead.

      
      // CORRECTED
import { calculateValue } from './utilities';

export function myStrategy() { ... }
export function otherStrategy() { ... }
export function someValueFactory() {
  return calculateValue();
}
  ...
  providers: [
    { provide: MyStrategy, useFactory: myStrategy },
    { provide: OtherStrategy, useFactory: otherStrategy },
    { provide: SomeValue, useFactory: someValueFactory }
  ]
  ...
    

不支援解構變數或常量 (Destructured variable or constant not supported)

Destructured variable or constant not supported

範本編譯器不支援參考匯出的解構語法的變數或常量。考慮簡化這一點,以避免解構語法。

Referencing an exported destructured variable or constant is not supported by the template compiler. Consider simplifying this to avoid destructuring.

編譯器不支援參考透過解構賦值的方式得到的變數。

The compiler does not support references to variables assigned by destructuring.

比如,你不能這麼寫:

For example, you cannot write something like this:

      
      // ERROR
import { configuration } from './configuration';

// destructured assignment to foo and bar
const {foo, bar} = configuration;
  ...
  providers: [
    {provide: Foo, useValue: foo},
    {provide: Bar, useValue: bar},
  ]
  ...
    

要糾正這個錯誤,就要參考非解構方式的變數。

To correct this error, refer to non-destructured values.

      
      // CORRECTED
import { configuration } from './configuration';
  ...
  providers: [
    {provide: Foo, useValue: configuration.foo},
    {provide: Bar, useValue: configuration.bar},
  ]
  ...
    

無法解析型別 (Could not resolve type)

Could not resolve type

編譯器遇到了某個型別,但是不知道它是由哪個模組匯出的。

The compiler encountered a type and can't determine which module exports that type.

這通常會發生在你參考環境型別時。 比如,Window 型別就是在全域性 .d.ts 檔案中宣告的環境型別。

This can happen if you refer to an ambient type. For example, the Window type is an ambient type declared in the global .d.ts file.

如果你在元件的建構函式中參考它就會導致一個錯誤,因為編譯器必須對建構函式進行靜態分析。

You'll get an error if you reference it in the component constructor, which the compiler must statically analyze.

      
      // ERROR
@Component({ })
export class MyComponent {
  constructor (private win: Window) { ... }
}
    

TypeScript 能理解這些環境型別,所以你不用匯入它們。 但 Angular 編譯器不理解你沒有匯入或匯出過的型別。

TypeScript understands ambient types so you don't import them. The Angular compiler does not understand a type that you neglect to export or import.

這種情況下,編譯器就無法理解如何使用這個 Window 令牌來進行注入。

In this case, the compiler doesn't understand how to inject something with the Window token.

不要在元資料表示式中參考環境型別。

Do not refer to ambient types in metadata expressions.

如果你必須注入某個環境型別的實例,可以用以下四步來巧妙解決這個問題:

If you must inject an instance of an ambient type, you can finesse the problem in four steps:

  1. 為環境型別的實例建立一個注入令牌。

    Create an injection token for an instance of the ambient type.

  2. 建立一個返回該實例的工廠函式。

    Create a factory function that returns that instance.

  3. 使用該工廠函式新增一個 useFactory 提供者。

    Add a useFactory provider with that factory function.

  4. 使用 @Inject 來注入這個實例。

    Use @Inject to inject the instance.

下面的例子說明了這一點。

Here's an illustrative example.

      
      // CORRECTED
import { Inject } 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) { ... }
}
    

對於編譯器來說,建構函式中出現 Window 型別已不再是個問題,因為它現在使用 @Inject(WINDOW) 來產生注入程式碼。

The Window type in the constructor is no longer a problem for the compiler because it uses the @Inject(WINDOW) to generate the injection code.

Angular 也用 DOCUMENT 令牌做了類似的事情,所以你也可以注入瀏覽器的 document 物件(或它的一個抽象層,取決於該應用執行在哪個平臺)。

Angular does something similar with the DOCUMENT token so you can inject the browser's document object (or an abstraction of it, depending upon the platform in which the application runs).

      
      import { Inject }   from '@angular/core';
import { DOCUMENT } from '@angular/common';

@Component({ ... })
export class MyComponent {
  constructor (@Inject(DOCUMENT) private doc: Document) { ... }
}
    

期望的名字 (Name expected)

Name expected

編譯器在正在計算的表示式中期望有一個名字。

The compiler expected a name in an expression it was evaluating.

如果將數字用作屬性名稱,則可能發生這種情況,如以下範例所示。

This can happen if you use a number as a property name as in the following example.

      
      // ERROR
provider: [{ provide: Foo, useValue: { 0: 'test' } }]
    

把該屬性的名字改為非數字型別。

Change the name of the property to something non-numeric.

      
      // CORRECTED
provider: [{ provide: Foo, useValue: { '0': 'test' } }]
    

不支援的列舉成員名稱 (Unsupported enum member name)

Unsupported enum member name

Angular 不能確定你在元資料中參考的列舉成員的值。

Angular couldn't determine the value of the enum member that you referenced in metadata.

編譯器可以理解簡單的列舉值,但不能理解複雜的,比如從那些計算屬性中派生出來的。

The compiler can understand simple enum values but not complex values such as those derived from computed properties.

      
      // 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
  ]
  ...
    

避免參考那些使用了複雜初始化物件或計算屬性的列舉。

Avoid referring to enums with complicated initializers or computed properties.

不支援帶標籤的範本表示式 (Tagged template expressions are not supported)

Tagged template expressions are not supported

元資料中不支援帶標籤函式的範本表示式。

Tagged template expressions are not supported in metadata.

編譯器遇到了 JavaScript ES2015 帶標記的範本表示式,如下所示。

The compiler encountered a JavaScript ES2015 tagged template expression such as the following.

      
      // ERROR
const expression = 'funky';
const raw = String.raw`A tagged template ${expression} string`;
 ...
 template: '<div>' + raw + '</div>'
 ...
    

String.raw()是一個 ES2015 原生的標籤函式

String.raw()is a tag function native to JavaScript ES2015.

AOT 編譯器不支援帶標籤函式的範本表示式,避免在元資料表示式中使用它們。

The AOT compiler does not support tagged template expressions; avoid them in metadata expressions.

期待符號的參考 (Symbol reference expected)

Symbol reference expected

編譯器期待在錯誤資訊指出的位置是一個符號參考。

The compiler expected a reference to a symbol at the location specified in the error message.

當你在類別的 extends 子句中使用表示式時就會出現這個錯誤。

This error can occur if you use an expression in the extends clause of a class.