Skip to content

Function vs VoidCallback in Dart null safety

Problem: Type mismatch with function parameters

When working with Flutter widgets and Dart's null safety, you may encounter the error:

"The argument type 'Function' can't be assigned to the parameter type 'void Function()?'"

This typically occurs when you're trying to pass a function parameter to widget callbacks like onPressed, onTap, or onChanged.

Original problematic code

dart
class DrawerItem extends StatelessWidget {
  final String text;
  final Function onPressed; // ❌ Problematic declaration

  const DrawerItem({Key key, this.text, this.onPressed}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return FlatButton(
      child: Text(text),
      onPressed: onPressed, // Error occurs here
    );
  }
}

Solutions

The most straightforward solution is to use VoidCallback instead of the generic Function type:

dart
class DrawerItem extends StatelessWidget {
  final String text;
  final VoidCallback onPressed; // ✅ Proper type

  const DrawerItem({Key key, this.text, this.onPressed}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      child: Text(text),
      onPressed: onPressed,
    );
  }
}

2. Use explicit function signature

Alternatively, you can be more explicit about the function signature:

dart
final void Function() onPressed; // ✅ Clear type definition

INFO

VoidCallback is simply a typedef for void Function(), so both approaches are equivalent.

3. Null-safe variants

If your function parameter might be null, use the nullable versions:

dart
final VoidCallback? onPressed; // ✅ Nullable callback
// or
final void Function()? onPressed; // ✅ Nullable callback

Why this error occurs

Dart's null safety requires precise type definitions. The generic Function type doesn't specify:

  • The return type (should be void)
  • The parameter list (should be empty ())
  • Nullability (whether it can be null)

Widget callbacks like onPressed expect specific function signatures that Function doesn't satisfy.

Advanced usage

Functions with parameters

If your callback needs parameters, be explicit about the signature:

dart
// For Checkbox or similar widgets
final void Function(bool?)? onChanged;

// For custom parameter callbacks
final void Function(String, int) onCustomEvent;

Calling multiple functions

For widgets that need to trigger multiple actions:

dart
ElevatedButton(
  child: Text('Submit'),
  onPressed: () {
    validateForm();
    submitData();
    navigateAway();
  },
)

Function shorthand

For simple single-function calls, use the arrow syntax:

dart
ElevatedButton(
  child: Text('Delete'),
  onPressed: () => deleteItem(), // ✅ Clean and concise
)

Common pitfalls to avoid

DANGER

Don't use dynamic as a workaround

dart
final dynamic onPressed; // ❌ Avoid this

// While this compiles, it sacrifices type safety
// and can lead to runtime errors

WARNING

Don't forget null safety

If you declare a nullable callback, ensure you handle null cases:

dart
onPressed: onPressed ?? () {} // Provide default empty function
// or
onPressed: onPressed ?? () => print('No action defined')

Best practices

  1. Prefer VoidCallback over Function for parameter-less void functions
  2. Be explicit about function signatures when parameters are needed
  3. Use null safety appropriately - mark callbacks as nullable if they're optional
  4. Avoid dynamic for function types as it bypasses type checking
  5. Consider using named parameters for better readability when passing functions

By following these patterns, you'll write more robust, null-safe Dart code that clearly communicates intent while avoiding common type errors.