Type inference

Domains: Dart

The analyzer can infer types for fields, methods, local variables, and most generic type arguments. When the analyzer doesn’t have enough information to infer a specific type, it uses the dynamic type.

Here’s an example of how type inference works with generics. In this example, a variable named arguments holds a map that pairs string keys with values of various types.

If you explicitly type the variable, you might write this:

Map<String, dynamic> arguments = {'argA': 'hello', 'argB': 42}; 

Alternatively, you can use var and let Dart infer the type:

var arguments = {'argA': 'hello', 'argB': 42}; // Map<String, Object> 

The map literal infers its type from its entries, and then the variable infers its type from the map literal’s type. In this map, the keys are both strings, but the values have different types (String and int, which have the upper bound Object). So the map literal has the type Map<String, Object>, and so does the arguments variable.

Field and method inference

A field or method that has no specified type and that overrides a field or method from the superclass, inherits the type of the superclass method or field.

A field that does not have a declared or inherited type but that is declared with an initial value, gets an inferred type based on the initial value.

Static field inference

Static fields and variables get their types inferred from their initializer. Note that inference fails if it encounters a cycle (that is, inferring a type for the variable depends on knowing the type of that variable).

Local variable inference

Local variable types are inferred from their initializer, if any. Subsequent assignments are not taken into account. This may mean that too precise a type may be inferred. If so, you can add a type annotation.

var x = 3; // x is inferred as an int x = 4.0; 
num y = 3; // a num can be double or int y = 4.0;

Type argument inference

Type arguments to constructor calls and generic method invocations are inferred based on a combination of downward information from the context of occurrence, and upward information from the arguments to the constructor or generic method. If inference is not doing what you want or expect, you can always explicitly specify the type arguments.

// Inferred as if you wrote <int>[]. 
List<int> listOfInt = []; 

// Inferred as if you wrote <double>[3.0]. 
var listOfDouble = [3.0]; 

// Inferred as Iterable<int> 
var ints = listOfDouble.map((x) => x.toInt()); 

In the last example, x is inferred as double using downward information. The return type of the closure is inferred as int using upward information. Dart uses this return type as upward information when inferring the map() method’s type argument: <int>.

Similar pages

Page structure
Terms

Map

String

Types

int

Methods

Dart

Variables

double

Lexical closures

Constructor

Generics