- 修复常见的类型问题
- Troubleshooting
- Am I really using type-safe Dart?
- Static errors and warnings
- Undefined member
- Example 1: A variable is statically known to be some supertype, but the code assumes a subtype
- Fix: Replace the definition of the member with an explicit type declaration or a downcast
- Example 2: Omitted type parameters default to their type bounds
- Fix: Specify type arguments or fix downstream errors
- Invalid method override
- Example
- Fix: Widen the method’s parameter types
- Missing type arguments
- Example
- Fix: Specify type arguments for the generic subclass
- Unexpected collection element type
- Example
- Fix: Specify the type explicitly
- Constructor initialization list super() call
- Example
- Fix: Put the super() call last
- The function expression type … isn’t of type …
- Example
- Fix: Add type parameters or cast from dynamic explicitly
- Undefined member
- Runtime errors
- Invalid casts
- Fix: Tighten or correct types
- Invalid casts
- Appendix
- The covariant keyword
- The covariant keyword
- Troubleshooting
修复常见的类型问题
If you’re having problems with type checks,this page can help. To learn more, read aboutDart’s type system,and see these other resources.
Help us improve this page! If you encounter a warning or error that isn’t listed here, please file an issue by clicking the bug icon at the top right. Include the warning or error message and, if possible, the code for both a small reproducible case and its correct equivalent.
Troubleshooting
Am I really using type-safe Dart?
If you’re not seeing expected errors or warnings,make sure that you’re using the latest version of Dart.
Alternatively, try adding the following code to a file:
- bool b = [0][0];
With type-safe Dart, the analyzer produces the following error:
error • A value of type 'int' can't be assigned to a variable of type 'bool' • invalid_assignment
Static errors and warnings
This section shows how to fix some of the errors and warningsyou might see from the analyzer or an IDE.
Static analysis can’t catch all errors.For help fixing errors that appear only at runtime,see Runtime errors.
Undefined member
error • The <member> '...' isn't defined for the class '...' • undefined_<member>
These errors can appear under the following conditions:
- A variable is statically known to be some supertype, but the code assumes a subtype.
- A generic class has a bounded type parameter, but an instance creationexpression of the class omits the type argument.
Example 1: A variable is statically known to be some supertype, but the code assumes a subtype
In the following code, the analyzer complains that context2D
is undefined:
- var canvas = querySelector('canvas');
- canvas.context2D.lineTo(x, y);
error • The getter 'context2D' isn't defined for the class 'Element' • undefined_getter
Fix: Replace the definition of the member with an explicit type declaration or a downcast
The querySelector()
method statically returns an Element,but the code assumes it returns the subtype CanvasElementwhere context2D
is defined.The canvas
field is declared as var
which,in Dart 1.x versions without strong mode,types it as dynamic
and silences all errors.Dart infers canvas
to be an Element.
You can fix this error with an explicit type declaration:
- CanvasElement canvas = querySelector('canvas');
- canvas.context2D.lineTo(x, y);
The code above passes static analysis when implicit casts are permitted.
You can also use an explicit downcast:
- var canvas = querySelector('canvas') as CanvasElement;
- canvas.context2D.lineTo(x, y);
Otherwise, use dynamic
in situations where you cannot use a single type:
- dynamic canvasOrImg = querySelector('canvas, img');
- var width = canvasOrImg.width;
Example 2: Omitted type parameters default to their type bounds
Consider the following generic class with a bounded type parameter that extendsIterable
:
- class C<T extends Iterable> {
- final T collection;
- C(this.collection);
- }
The following code creates a new instance of this class (omitting the typeargument) and accesses its collection
member:
- var c = C(Iterable.empty()).collection;
- c.add(2);
error • The method 'add' isn't defined for the class 'Iterable'. • lib/bounded/instantiate_to_bound.dart:7:5 • undefined_method
While the List type has an add()
method, Iterable does not.
Fix: Specify type arguments or fix downstream errors
In Dart 1.x, when a generic class is instantiated without explicit typearguments, dynamic
is assumed. That is why, in the code excerpt above, c
isof type dynamic
and no error is reported for c.add()
.
In Dart 2, when a generic class is instantiated without explicit type arguments,each type parameter defaults to its type bound (Iterable
in this example) ifone is explicitly given, or dynamic
otherwise.
You need to approach fixing such errors on a case-by-case basis. It helps tohave a good understanding of the original design intent.
Explicitly passing type arguments is an effective way to help identify typeerrors. For example, if you change the code to specify List
as a typeargument, the analyzer can detect the type mismatch in the constructor argument.Fix the error by providing a constructor argument of the appropriate type:
- var c = C<List>([]).collection;
- c.add(2);
Invalid method override
error • '...' isn't a valid override of '...' • invalid_override
These errors typically occur when a subclass tightens up a method’sparameter types by specifying a subclass of the original class.
备忘: This issue can also occur when a generic subclass neglects to specify a type. For more information, see Missing type arguments.
Example
In the following example, the parameters to the add()
method are of type int
,a subtype of num
, which is the parameter type used in the parent class.
- abstract class NumberAdder {
- num add(num a, num b);
- }
- class MyAdder extends NumberAdder {
- int add(int a, int b) => a + b;
- }
error • 'MyAdder.add' ('int Function(int, int)') isn't a valid override of 'NumberAdder.add' ('num Function(num, num)') • invalid_override
Consider the following scenario where floatingpoint values are passed to an MyAdder:
- NumberAdder adder = MyAdder();
- adder.add(1.2, 3.4);
If the override were allowed, the code would raise an error at runtime.
Fix: Widen the method’s parameter types
The subclass’s method should accept everyobject that the superclass’s method takes.
Fix the example by widening the types in the subclass:
- abstract class NumberAdder {
- num add(num a, num b);
- }
- class MyAdder extends NumberAdder {
- num add(num a, num b) => a + b;
- }
For more information, see Use proper input parameter types when overriding methods.
备忘: If you have a valid reason to use a subtype, you can use the covariant keyword.
Missing type arguments
error • '...' isn't a valid override of '...' • invalid_override
Example
In the following example, Subclass
extends Superclass<T>
but doesn’tspecify a type argument. The analyzer infers Subclass<dynamic>
,which results in an invalid override error on method(int)
.
- class Superclass<T> {
- void method(T t) { ... }
- }
- class Subclass extends Superclass {
- void method(int i) { ... }
- }
error • 'Subclass.method' ('void Function(int)') isn't a valid override of 'Superclass.method' ('void Function(dynamic)') • invalid_override
Fix: Specify type arguments for the generic subclass
When a generic subclass neglects to specify a type argument,the analyzer infers the dynamic
type. This is likely to causeerrors.
You can fix the example by specifying the type on the subclass:
- class Superclass<T> {
- void method(T t) { ... }
- }
- class Subclass extends Superclass<int> {
- void method(int i) { ... }
- }
Unexpected collection element type
error • A value of type '...' can't be assigned to a variable of type '...' • invalid_assignment
This sometimes happens when you create a simple dynamic collectionand the analyzer infers the type in a way you didn’t expect.When you later add values of a different type, the analyzer reports an issue.
Example
The following code initializes a map with several(String, int) pairs. The analyzer infers that map to be of type<String, int>
but the code seems to assume either <String, dynamic>
or <String, num>
.When the code adds a (String, float) pair, the analyzer complains:
- // Inferred as Map<String, int>
- var map = {'a': 1, 'b': 2, 'c': 3};
- map['d'] = 1.5; // a double is not an int
error • A value of type 'double' can't be assigned to a variable of type 'int' • invalid_assignment
Fix: Specify the type explicitly
The example can be fixed by explicitly defining the map’s type to be<String, num>
.
- var map = <String, num>{'a': 1, 'b': 2, 'c': 3};
- map['d'] = 1.5;
Alternatively, if you want this map to accept any value, specify the type as <String, dynamic>
.
Constructor initialization list super() call
error • The super call must be last in an initializer list (see https://goo.gl/EY6hDP): '...' • invalid_super_invocation
This error occurs when the super()
call is not last in a constructor’sinitialization list.
Example
- HoneyBadger(Eats food, String name)
- : super(food),
- _name = name { ... }
error • The super call must be last in an initializer list (see https://goo.gl/EY6hDP): 'super(food)' • invalid_super_invocation
Fix: Put the super() call last
The compiler can generate simpler code if it relies on the super()
call appearing last.
Fix this error by moving the super()
call:
- HoneyBadger(Eats food, String name)
- : _name = name,
- super(food) { ... }
The function expression type … isn’t of type …
error • The function expression type '...' isn't of type '...'. This means its parameter or return type doesn't match what is expected. Consider changing parameter type(s) or the returned type(s) • invalid_cast_function_expr
In Dart 1.x dynamic
was both a top type (supertype of all types) and abottom type (subtype of all types)depending on the context. This meant it was valid to assign, for example,a function with a parameter of type String
to a place that expected afunction type with a parameter of dynamic
.
However, in Dart 2 passing something other than dynamic
(or another _top_type, such as Object
, or a specific bottom type, such as Null
) resultsin a compile-time error.
Example
- typedef Filter = bool Function(dynamic any);
- Filter filter = (String x) => x.contains('Hello');
error • The function expression type 'bool Function(String)' isn't of type 'bool Function(dynamic)'. This means its parameter or return type doesn't match what is expected. Consider changing parameter type(s) or the returned type(s) • invalid_cast_function_expr
Fix: Add type parameters or cast from dynamic explicitly
When possible, avoid this error by adding type parameters:
- typedef Filter<T> = bool Function(T any);
- Filter<String> filter = (String x) => x.contains('Hello');
Otherwise use casting:
- typedef Filter = bool Function(dynamic any);
- Filter filter = (x) => (x as String).contains('Hello');
Runtime errors
Unlike Dart 1.x, Dart 2 enforces a sound type system. Roughly, this meansyou can’t get into a situation where the value stored in a variable isdifferent than the variable’s static type. Like most modern staticallytyped languages, Dart accomplishes this with a combination of static(compile-time) and dynamic (runtime) checking.
For example, the following type error is detected at compile-time(when the implicit casts option is disabled):
- List<int> numbers = [1, 2, 3];
- List<String> string = numbers;
Since neither List<int>
nor List<String>
is a subtype of the other,Dart rules this out statically. You can see other examples of thesestatic analysis errors in Unexpected collection element type.
The errors discussed in the remainder of this section are reported atruntime.
Invalid casts
To ensure type safety, Dart needs to insert runtime checks in some cases. Consider:
- assumeStrings(List<Object> objects) {
- List<String> strings = objects; // Runtime downcast check
- String string = strings[0]; // Expect a String value
- }
The assignment to strings
is downcasting the List<Object>
to List<String>
implicitly (as if you wrote as List<String>
), so if the value you pass inobjects
at runtime is a List<String>
, then the cast succeeds.
Otherwise, the cast will fail at runtime:
- assumeStrings(<int>[1, 2, 3]);
Exception: type 'List<int>' is not a subtype of type 'List<String>'
Fix: Tighten or correct types
Sometimes, lack of a type, especially with empty collections, means that a <dynamic>
collection is created, instead of the typed one you intended. Adding an explicittype argument can help:
- var list = <String>[];
- list.add('a string');
- list.add('another');
- assumeStrings(list);
You can also more precisely type the local variable, and let inference help:
- List<String> list = [];
- list.add('a string');
- list.add('another');
- assumeStrings(list);
In cases where you are working with a collection that you don’t create, suchas from JSON or an external data source, you can use thecast() methodprovided by List
and other collection classes.
Here’s an example of the preferred solution: tightening the object’s type.
- Map<String, dynamic> json = fetchFromExternalSource();
- var names = json['names'] as List;
- assumeStrings(names.cast<String>());
版本提示: The cast()
method was introduced in 2.0.0-dev.22.0.
If you can’t tighten the type or use cast
, you can copy the objectin a different way. For example:
- Map<String, dynamic> json = fetchFromExternalSource();
- var names = json['names'] as List;
- // Use `as` and `toList` until 2.0.0-dev.22.0, when `cast` is available:
- assumeStrings(names.map((name) => name as String).toList());
Appendix
The covariant keyword
Some (rarely used) coding patterns rely on tightening a typeby overriding a parameter’s type with a subtype, which is invalid.In this case, you can use the covariant
keyword totell the analyzer that you are doing this intentionally.This removes the static error and instead checks for an invalidargument type at runtime.
版本提示: The covariant
keyword was introduced in 1.22. It replaces the @checked
annotation.
The following shows how you might use covariant
:
- class Animal {
- void chase(Animal x) { ... }
- }
- class Mouse extends Animal { ... }
- class Cat extends Animal {
- void chase(covariant Mouse x) { ... }
- }
Although this example shows using covariant
in the subtype,the covariant
keyword can be placed in either the superclassor the subclass method.Usually the superclass method is the best place to put it.The covariant
keyword applies to a single parameter and isalso supported on setters and fields.