In Dart, how do you write a function type such as `int Function(String)`, and where can you use one?
answer
- mirror of a function header
- name swapped for a keyword
- positional names optional, named names kept
- anywhere a type annotation goes
- nullable callback: ?.call()
basics
~20 sA Dart function type is a function header with its name replaced by the keyword Function: int Function(String) accepts one String and returns an int. It can annotate parameters, fields, variables, return types and type arguments.
solid answer
~40 sDart builds a function type by taking a function's header and swapping the name for the keyword `Function`, so `int Function(String)` is any function that takes one positional `String` and returns an `int`. Positional parameter names are optional and only document intent, but named parameters must keep their names because callers pass them by name: `void Function(String, {required int retries})`. Optional positionals go in square brackets, just as in a declaration. The type works anywhere a type annotation does: a callback parameter, a field, a local, a return type, or a type argument such as `List<void Function()>`. For an optional callback make the type nullable, `void Function()?`, and invoke it with `onDone?.call()`.
code
dart · 11 linesvoid greet(String name, {String greeting = 'Hello'}) =>
print('$greeting $name!');
void Function(String, {String greeting}) g = greet;
List<int Function(int)> steps = [(x) => x + 1, (x) => x * 2];
void main() {
g('Dash', greeting: 'Howdy');
print(steps.fold(3, (acc, step) => step(acc))); // 8
}go deeper
Be able to write int Function(String) from memory, use it on a callback parameter, and say that positional names are optional while named ones are required.
Explain every position a function type may occupy, how optional and named parameters are spelled inside it, and why a nullable callback is invoked through ?.call().
Show that you design APIs with precise callback signatures, including required named parameters, and recognise the older function-typed parameter style that the recommended lints flag.
Treat callback signatures as public contracts: adding a required parameter to a function type breaks every caller that passes a function, so shape them deliberately and early.
## What a function type is In Dart, functions are **first-class objects**: a function can be stored in a variable, passed as an argument and returned from another function. To do that safely the type system needs a way to describe *which* functions fit a slot. That description is a **function type**. The rule is mechanical: take a function declaration's header and replace the function's **name** with the keyword `Function`. ```dart int parseScore(String raw) => int.parse(raw); int Function(String) parser = parseScore; // the type of parseScore void main() { print(parser('42')); // 42 } ``` Read `int Function(String)` as: **return type** `int`, then the keyword, then the **parameter list** `(String)`. Nothing else is needed; no interface, no declaration, no typedef. Any function whose shape matches can be assigned. ## Writing the parameter list The parameter list inside a function type follows the same grammar as a declaration, with one relaxation and one restriction: - **Positional parameter names are optional.** `int Function(String)` and `int Function(String raw)` are the same type; the name is documentation only. - **Named parameter names are mandatory.** Callers pass named arguments by name, so the name is part of the contract: `void Function({required int retries})`. - **Optional positional parameters** go in square brackets: `String Function(String, [int])`. - **Required named parameters** carry `required`, exactly as in a declaration. - **Generic function types** put type parameters after the keyword: `T Function<T>(T)` is the type of a function that is itself generic. - A function with *extra optional* parameters still fits a shorter type, because it can be called with fewer arguments. Because positional names are ignored, `bool Function(String a)` and `bool Function(String b)` are the same type, and the core `print` function, declared as `void print(Object? object)`, fits `void Function(Object?)` whatever its parameter is called. Named parameters behave differently: `void Function({int? limit})` and `void Function({int? max})` are distinct types, and a function declared with `{int? limit}` fits only the first. Renaming a named parameter in a public callback type is therefore a breaking change for every function that callers pass in. ## Where a function type can appear A function type is an ordinary type, so it is legal anywhere a type annotation is: 1. A **parameter**: `void retry(Future<void> Function() action)`. 2. A **field**: `final bool Function(String) isAllowed;`. 3. A **local variable**: `int Function(String) parser = parseScore;`. 4. A **return type**: `bool Function(String) longerThan(int n) => (s) => s.length > n;`. 5. A **type argument**: `List<void Function()> listeners = [];`. 6. A **record field**: `({String label, void Function()? onPressed})`. ## Nullable callbacks and `call` Optional callbacks are very common, so the type is often nullable: `void Function()? onDone`. Every function type has a `call` method with the same signature as the type itself, and calling `call` behaves exactly like calling the function. That is what makes the idiom work: ```dart class Uploader { Uploader({this.onDone}); final void Function()? onDone; void finish() => onDone?.call(); // skipped when onDone is null } ``` Writing `onDone()` directly does not compile while the type is nullable. An `if (onDone != null) onDone();` check does not help either, because Dart promotes only private final fields (since 3.2), never a public one like this; `?.call()` is the concise, sound form. ## Three ways to type a callback parameter | Style | Example | Status | |---|---|---| | **Function type syntax** | `bool Function(String) test` | Recommended everywhere | | **Function-typed formal parameter** | `bool test(String s)` | Still valid; the `use_function_type_syntax_for_parameters` lint (recommended set) flags it | | **Bare `Function`** | `Function test` | Compiles, but carries no signature and makes every call dynamic | The older C-like style is not wrong, but the function type syntax is the one that works in every position, so Effective Dart asks you to use it for parameters too. ## What interviewers listen for - Writing the type without hesitation, with the return type *before* `Function`. - Knowing that named parameters keep their names and positional ones need not. - Choosing `void Function()?` plus `?.call()` for optional callbacks. - Not reaching for a typedef by reflex: inline function types are the default recommendation, and a typedef is only an alias for the same type. - Not confusing Dart's syntax with arrow-style type notation from other languages; `(String) => int` is not a type annotation in Dart.
- Why must named parameters keep their names in a Dart function type when positional ones need not?Callers pass named arguments by name, so the name is part of the function's contract: `void Function({required int retries})` and `void Function({required int attempts})` are different types. Positional arguments are matched by position, so a positional name inside a function type is documentation only and changes nothing about which functions fit.
- Can a function with an extra optional parameter be stored in a `void Function(String)` variable?Yes. `void log(String msg, [int level = 0])` can be called with a single `String`, so it satisfies `void Function(String)`; the extra parameter keeps its default. The reverse fails: a function that requires two arguments cannot sit where callers will pass only one.
saying these in an interview costs you the question
- Writing (String) => int as a Dart type annotation
- Believing named parameters can be left unnamed in a function type
- Thinking a typedef is required before a function type can be used
- Calling a nullable callback directly and expecting a runtime null check
- Putting the return type after the parameter list