avoid-types-on-closure-parameters
Same as avoid_types_on_closure_parameters in Dart lints
- Group
- Style
- Path
lint/style/avoid-types-on-closure-parameters- Default
- Off, opt in
- Origin
- Dart lints
- Rule
- 150 of 512
Flags type annotations on closure parameters whose types come from context.
When a function expression is passed where a function type is expected,
its parameter types are inferred from that type, so annotating them is
redundant. Closures without a known function-typed context are left alone
because their annotations carry information. Like the official lint, a
closure that is an operand, an await operand, a switch expression arm,
a record literal field, or a direct collection literal element/key/value
(including collection if/for) has no context here. This does not suppress
independently contextualized callbacks nested inside those expressions.
Parenthesizing an operand (including the fallback of ??) does not add context.
A returned closure has context only in an async body returning Future<F>
for a function type F. A conditional branch or assignment RHS takes its
enclosing expression's own static type as its context, including function
types obtained by joining variant signatures. Joins retain the shared
optional positional prefix when required arity agrees. Different required
arities join to general Function, unless a concrete downward function
context provides a shared signature.
names.map((String name) => name.length); // flagged
names.map((name) => name.length); // ok
Invalid
int apply(int Function(int) fn) => fn(1);
void each(List<String> names, void Function(String name) action) {}
void entries(void Function(String key, int value) action) {}
void typed(void Function(void Function() inner) action) {}
void f(List<String> names) {
apply((int x) => x + 1);
each(names, (String name) {
print(name);
});
entries((String key, int value) {});
entries((key, int value) {});
typed((void inner()) {});
final int Function(int) inc = (int x) => x + 1;
print(inc);
}
// An `async` body returning `Future<F>` gives a returned closure context `F`.
Future<int Function(int)> later() async {
return (int x) => x;
}
final Future<int Function(int)> Function() deferred = () async {
return (int x) => x;
};
void sink(Object value) {}
// A conditional branch's context is the conditional's own static type.
void conditional(bool b) {
sink(b ? (int x) => x : (int x) => -x);
}
class CallbackBox {
const CallbackBox.named(this.callback);
final void Function(int) callback;
}
void contravariantAndFieldFormal() {
// The annotation need not equal the context's parameter type.
new CallbackBox.named((Object value) {});
}void f(List<String> names) { apply((int x) => x + 1); apply((int x) => x + 1); each(names, (String name) { }); entries((String key, int value) {}); }); entries((String key, int value) {}); entries((String key, int value) {}); entries((key, int value) {}); entries((key, int value) {}); typed((void inner()) {}); typed((void inner()) {}); final int Function(int) inc = (int x) => x + 1;Future<int Function(int)> later() async { return (int x) => x;final Future<int Function(int)> Function() deferred = () async { return (int x) => x;void conditional(bool b) { sink(b ? (int x) => x : (int x) => -x);void conditional(bool b) { sink(b ? (int x) => x : (int x) => -x); // The annotation need not equal the context's parameter type. new CallbackBox.named((Object value) {});Valid
import 'dart:async';
int apply(int Function(int) fn) => fn(1);
void each(List<String> names, void Function(String name) action) {}
void dyn(void Function(dynamic value) action) {}
void untypedContext(Function action) {}
void f(List<String> names) {
apply((x) => x + 1);
each(names, (name) {
print(name);
});
dyn((dynamic value) {});
untypedContext((int x) => x);
final g = (int x) => x;
var h = (String s) {};
print([g, h]);
}
// The official context approximation does not reach returned values, unless
// an `async` body returns `Future<F>`, nor operands or switch expression arms.
int Function(int) returned() {
return (int x) => x;
}
FutureOr<int Function(int)> eventually() async {
return (int x) => x;
}
void operand(List<String> names, int Function(String a, String b)? compare) {
names.sort(compare ?? (String a, String b) => a.compareTo(b));
}
void arms(bool flag, List<int> values) {
values.where(switch (flag) {
true => (int value) => value > 0,
false => (int value) => value < 0,
});
}
// Nor record literal fields, even under a record context type.
void fields(List<(int, void Function(String))> entries) {
entries.add((1, (String s) {}));
final (int, {void Function(String) named}) record = (2, named: (String s) {});
print(record);
}
typedef Any = dynamic;
void aliasContext(void Function(dynamic) callback) {}
void dynamicAlias() {
aliasContext((Any value) {});
}
class Sequence<T extends Object> {
const Sequence.single(T value);
}
void consumeSequences(List<Sequence> values) {}
void downwardConstructorContext() {
// The raw contextual Sequence fixes T to Object, not the closure's type.
consumeSequences([Sequence.single((Object value) {})]);
}Configure avoid-types-on-closure-parameters
Set its severity in falcon.json. See the configuration guide.
{
"linter": {
"rules": {
"style": {
"avoid-types-on-closure-parameters": "error"
}
}
}
}Or silence one occurrence with a suppression comment; the reason is required.
// falcon-ignore lint/style/avoid-types-on-closure-parameters: <reason>More style rules
- avoid-unnecessary-block
Flags standalone nested blocks that introduce no lexical declarations.
- avoid-unnecessary-call
Prefer direct invocation of functions and resolved callable instances.
- avoid-unnecessary-continue
Flags an unlabeled continue at the end of a loop body or its final branch.
- avoid-unnecessary-getter
Flags a getter that only exposes a private final field.
- avoid-unnecessary-if
Flags an if branch that only returns the same expression as the following return.
- avoid-unnecessary-length-check
Empty collections already skip
for-inandforEachbodies. - avoid-unnecessary-local-variable
Reports a single-use local used only to initialize the next local.
- avoid-unnecessary-negations
Simplifies negated bool literals and equality comparisons with a logical negation on both sides.