Rules / Correctness / unnecessary-nullable-return-type
unnecessary-nullable-return-type
Disallow nullable return types on functions that never return null.
Flags a function or method whose return type is nullable (T?) even though
every return in its body yields a provably non-null value. A needless ?
forces callers to null-check a result that can never be null, spreading
defensive code that adds no safety. Drop the ? from the return type. Only
the outer nullability counts, so Future<T?> and List<int?> are left
alone. Without full type resolution the check is conservative: it fires only
when the body has at least one return and every returned expression is a
literal or constructor invocation — any return it cannot prove non-null (a
variable, a call, await, or a bare return;) suppresses the report.
Invalid
example.dartdart
// Bad: an outer-nullable return type whose every return is a non-null literal.
String? getStatus() {
return 'active';
}
int? getNumber() {
return 42;
}
// The outer `?` (after `List<...>`) counts; the returned list is non-null.
List<String?>? getItems() {
return ['a', 'b', 'c'];
}
bool? isValid() {
if (DateTime.now().isUtc) {
return true;
}
return false;
}
Function return type is unnecessarily nullable
2
3String? getStatus() {
∙
Function return type is unnecessarily nullable
Function return type is unnecessarily nullable
11// The outer `?` (after `List<...>`) counts; the returned list is non-null.
12List<String?>? getItems() {
∙
Function return type is unnecessarily nullable
Valid
example.dartdart
// Good: return type is non-nullable when function never returns null
Future<String> getName() async {
return 'hello';
}
String getStatus() {
return 'active';
}
int getNumber() {
return 42;
}
List<String> getItems() {
return ['a', 'b', 'c'];
}
Future<bool> isValid() async {
return true;
}
// Good: nullable return type when function can return null
String? maybeGetName(bool shouldReturn) {
if (shouldReturn) {
return 'hello';
}
return null;
}
int? findIndex(List<int> items, int target) {
try {
return items.indexOf(target);
} catch (e) {
return null;
}
}
// Good: only the OUTER `?` counts — a nullable type argument does not.
Future<String?> asyncName() async {
return 'hello';
}
Future<bool?> asyncValid() async {
return true;
}
// Good: returns we cannot prove non-null are not flagged.
String? fromVariable(String value) {
return value;
}
String? fromCall() {
return compute();
}
String? withNullBranch(bool flag) {
if (flag) {
return 'x';
}
return null;
}
How to configure
Set the severity of unnecessary-nullable-return-type in your falcon.json:
falcon.jsonjson
{
"linter": {
"rules": {
"correctness": {
"unnecessary-nullable-return-type": "error"
}
}
}
}