Skip to main content
A generic method in Dart is a function or method that declares one or more formal type parameters. These type parameters allow the method to operate on abstract types while enforcing strict compile-time type safety, deferring concrete type resolution until the method is invoked.

Syntax and Scope

Type parameters are enclosed in angle brackets (<...>) and positioned immediately after the method name, preceding the parameter list.
void methodName<T>(T parameter) {
  // Method body
}
Once declared, the type parameter (T) enters the method’s lexical scope and can be utilized in several distinct contexts:
  1. Return type: Defining the type of the value returned by the method.
  2. Parameter types: Defining the types of the arguments accepted by the method.
  3. Local variables: Defining the types of variables declared within the method body.
  4. Type tests and casts: Utilizing the type parameter in is and as expressions (e.g., value is T, value as T).
  5. Type arguments for generics: Passing the type parameter to other generic classes, collections, or methods (e.g., List<T>).
T processItem<T>(T item, dynamic unknownValue) {
  if (unknownValue is T) {                  // Type test
    T localVariable = unknownValue;         // Local variable
    List<T> list = [item, localVariable];   // Type argument for collection
    return list.last;                       // Return type
  }
  return unknownValue as T;                 // Type cast
}

Multiple Type Parameters

A generic method can declare multiple type parameters by separating them with commas. Each parameter operates independently within the method’s scope.
Map<K, V> pairItems<K, V>(K key, V value) {
  return {key: value};
}

Type Bounds (Constraints)

By default, a type parameter accepts any Dart object (equivalent to <T extends Object?>). To restrict the acceptable types, Dart uses the extends keyword to establish an upper bound. The generic method will only accept types that are subtypes of the specified bound.
// T is constrained to num or its subtypes (int, double)
T getLarger<T extends num>(T a, T b) {
  return a > b ? a : b; 
}

Invocation and Type Inference

When invoking a generic method, concrete types can be passed explicitly within angle brackets at the call site.
// Explicit type declaration
getLarger<int>(10, 20);
However, the Dart analyzer employs type inference. If the type arguments are omitted, the compiler infers the concrete type based on the static types of the provided arguments or the expected return context.
// Implicit type inference (T is inferred as double based on the arguments)
getLarger(10.5, 20.5);
Tired of Poor Dart Skills? Fix That With Deep Grasping!Learn More