Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The covariant keyword in Dart overrides the standard static type checking rules for method parameters during inheritance, allowing a subclass to tighten the type of an overridden method’s parameter to a subtype of the superclass’s parameter type. By default, Dart enforces the Liskov Substitution Principle (LSP), which dictates that method parameters in subclasses must be contravariant or invariant. This means a subclass cannot restrict an overridden method to accept a narrower type than the superclass method. The covariant keyword explicitly instructs the Dart analyzer to bypass this compile-time restriction and defer the type check to runtime.

Syntax and Mechanics

When a subclass overrides a method, attempting to narrow the parameter type results in a compile-time error. Applying covariant to the parameter in the subclass resolves this.
class Animal {}
class Cat extends Animal {}

class Caretaker {
  void feed(Animal animal) {}
}

class CatCaretaker extends Caretaker {
  // Without 'covariant', the analyzer throws:
  // "The parameter 'animal' of 'CatCaretaker.feed' has type 'Cat', 
  // which does not match the corresponding type, 'Animal', in the overridden method."
  
  @override
  void feed(covariant Cat animal) {
    // Parameter is now strictly typed as 'Cat' within this scope
  }
}

Superclass Declaration

The covariant keyword can also be applied directly to the parameter in the superclass or interface. When declared in the superclass, the covariance contract is inherited, and subclasses can narrow the parameter type without needing to redeclare the keyword.
abstract class Caretaker {
  // Declaring covariance at the abstraction level
  void feed(covariant Animal animal);
}

class CatCaretaker extends Caretaker {
  @override
  void feed(Cat animal) {
    // Valid: 'covariant' is implicitly inherited from Caretaker
  }
}

class Dog extends Animal {}

class DogCaretaker extends Caretaker {
  @override
  void feed(Dog animal) {
    // Valid: 'covariant' is implicitly inherited from Caretaker
  }
}

Runtime Implications

Because covariant suppresses compile-time static analysis for that specific parameter, type safety is enforced by the Dart Virtual Machine (VM) at runtime. If an instance of the subclass is accessed via a superclass reference and an invalid type is passed, the compiler will allow it, but the VM will throw a TypeError.
Caretaker caretaker = CatCaretaker();

// Static analysis passes because Caretaker.feed accepts Animal.
// Runtime execution succeeds because Cat matches the covariant CatCaretaker signature.
caretaker.feed(Cat()); 

// Static analysis passes because Caretaker.feed accepts Animal.
// Runtime execution FAILS and throws a TypeError because CatCaretaker expects a Cat.
caretaker.feed(Animal()); 
Master Dart with Deep Grasping Methodology!Learn More