avoid_unnecessary_option
This rule flags a local variable holding an Option that is never composed — wrapped, then immediately unwrapped with toNullable or getOrElse.
Why use this rule
Section titled “Why use this rule”Option earns its keep through its combinators: chaining with flatMap, promoting absence to a failure with toEither, providing a fallback with alt. A local that is wrapped and then unwrapped on the next line gets none of that, and pays for it — Dart’s nullable types have language support (?., ??, narrowing after a null check) that Option cannot match.
fpdart’s own author makes the same point: Option<T> and T? are not mutually exclusive. Nullable wins on language support, Option wins on declarative chaining, and the right move is to convert at the border rather than fight the language.
See also: Option type and null safety in Dart
final option = Option.fromNullable(name);final value = option.toNullable() ?? 'unknown';Either drop the wrapper:
final value = name ?? 'unknown';Or earn it, by actually composing:
final value = Option.fromNullable(name) .map(deriveDisplayName) .alt(() => some(defaultName)) .getOrElse(() => 'unknown');Known limitations
Section titled “Known limitations”Only local variables are reported. A field or a parameter is part of a type’s shape, and reporting it would be a claim about the API rather than about one expression.
A local inside a public member is skipped by default, since its Option may be feeding a contract. Set ignore_public_api: false to report those too.
An Option passed to a function, returned, or matched with a pattern counts as composed — the wrapper is doing work in all three.
No quick fix is offered: rewriting to a nullable means adjusting every downstream use, which is a change to read rather than apply.
Options
Section titled “Options”many_lints: rules: avoid_unnecessary_option: ignore_public_api: falserules: avoid_unnecessary_option: ignore_public_api: false| Option | Type | Default | Description |
|---|---|---|---|
ignore_public_api |
bool | true |
Skip locals inside public members, whose Option may be feeding a contract |
Configuration
Section titled “Configuration”This rule is in the pedantic preset — a codebase that has standardised on Option
everywhere is making a coherent choice, and this rule disagrees with it. It can
also be enabled explicitly:
rules: avoid_unnecessary_option: trueTo keep the rule on but skip certain paths, use per-rule exclude.
Related rules
Section titled “Related rules”prefer_from_nullable— A null check that builds an Option by hand is what Option.fromNullable is for.prefer_from_predicate— A conditional guarding an Option is one Option.fromPredicate call.avoid_future_of_option— Future<Option> throws away the composition TaskOption already gives you.avoid_ad_hoc_left_type— A pipeline only composes when every step shares one error type.