Skip to main content
A generic method is a function that declares one or more type parameters within its signature, allowing the specific data types to be resolved at the call site or inferred by the compiler. This mechanism enables a single method implementation to operate uniformly across different types while maintaining static type safety.

Syntax Declaration

Type parameters are declared inside angle brackets (< >) immediately following the method name and preceding the parameter list.
// Top-level function
T identify<T>(T value) {
  return value;
}

class Utils {
  // Static method within a class
  static T extract<T>(List<T> list) {
    return list[0];
  }
}
Components:
  1. <T>: The declaration of the type parameter. T serves as a placeholder for the actual type.
  2. T value: Usage of the type parameter as a formal parameter type.
  3. T (Return Type): Usage of the type parameter as the return type.

Type Parameter Scope

The scope of a generic method’s type parameter is limited to the method itself. It applies to:
  • The return type.
  • The formal parameters.
  • Local variables declared within the method body.
If a generic method is defined inside a generic class, the method’s type parameter shadows the class’s type parameter if they share the same name.

Invocation

Generic methods can be invoked using explicit type arguments or through type inference.

Explicit Invocation

The caller specifies the type argument inside angle brackets.
void main() {
  // Explicitly passing 'int' as the type argument
  var result = identify<int>(42);
}

Type Inference

If the context provides sufficient information, the Dart compiler infers the type argument automatically.
void main() {
  // Compiler infers <String> based on the argument "Hello"
  var result = identify("Hello");
}

Restricted Type Parameters (Bounds)

Type parameters can be constrained using the extends keyword. This restricts the allowed types to a specific class or its subclasses (or types that implement a specific interface), granting the method access to members defined in the bound.
// T must be a subclass of num (e.g., int or double)
T max<T extends num>(T a, T b) {
  // Accessing .compareTo or operators available on num
  return a > b ? a : b;
}

Reified Types

Dart generics are reified, meaning type information is retained at runtime rather than being erased. Consequently, a generic method can perform type checks (is), type casts (as), and type introspection using the type parameter within its body. Note: While types are reified, Dart does not support instantiating a type parameter directly (e.g., new T() is a compile-time error).
void checkType<T>() {
  // Runtime check against the type parameter
  if (T == int) {
    print("Type is integer");
  }
  print("Runtime type: $T");
}
Master Dart with Deep Grasping Methodology!Learn More