Effective Dart Tricks
Tags: dart, programming, style, effective
Published: 2021-05-11 16:03:36

No intro here, let's jump into some effective Dart language tricks and features.

## Trick 1: Use the linter!

You're probably using VS Code or Android studio for development in Dart or Flutter projects. Anytime you see the red, blue, grey, or <insert some theme-defined color here> squiggles underneath your "bad" code - that's the linter at work.

All Dart and Flutter linter rules can be found [here](https://dart-lang.github.io/linter/lints/). See if any of these tickle your fancy.

To add one of these rules to your project, follow these steps:

1. Create a new `analysis_options.yaml` file at the root off your project. This will be in the same directory as your `pubspec.yaml` file.

2. Add the following snippet to tell your editor's analysis server there are some rules you'll be adding:

  ```yaml
linter:
  rules:
  ```

3. Select a rule from [the list](https://dart-lang.github.io/linter/lints/) and add it to your `analysis_options.yaml`


```yaml
linter:
  rules:
    - lines_longer_than_80_chars
    - another_rule # add any rule from that list here
```

## Trick 2: Prevent classes from being inherited and instantiated

Typically, an `abstract` class would be used to create a non-instantiatable class. But occassionally you'll have a class you don't want inherited as well.

The Flutter SDK usees this trick internally with [`Curves`](https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/animation/curves.dart#L1406) and other classes.

```dart
class SomeClass {
  SomeClass._(); // Use a private, unnamed constructor.

  /// All members should now be static.
  static const name = 'SomeClass';

  /// Methods should be pure and static as well.
  static String someFunction(String person) => 'Hello, $person!';
}
```

Use a private, unnamed constructor. To use any member with this class, you should use the key word `static`. Since static objects are class-level (not instance-level). It operates similarly to an `enum` object when accessing values, but this is a bit more robust for those certain circumstances.

## Trick 3: Implementing you own operator for an object

The `+`, `-`, and `/` are all examples of operators that can be overwritten for your class. For example, let's create a class that you want to add two values objects together to achieve a deterministic result.

With coordinate points, we know you can add two points together to get a *new* point value. Here, we'll demonstrate that simply by defining the behavior of the `+` operator.

```dart
class Point {
  Point(this.x, this.y);

  final int x;
  final int y;

  /// Sum of two points.
  Point operator +(Point other) => Point(
        this.x + other.x,
        this.y + other.y,
      );
}
```

This functionality can also be achieved on *existing* classes with an `extension`.

```dart
extension DateTimeOperators on DateTime {

  /// Date after a [duration] of time.
  DateTime operator +(Duration duration) => this.add(duration);

  /// Difference between [this] duration the [other].
  Duration operator -(DateTime other) => this.difference(other);
}
```

PS: for a full list of operator that can be used check out [this section](https://dart.dev/guides/language/language-tour#_operators) of Dart's language tour.

## Trick 4: Use `typedef` to keep code concise.

The `typedef` key word is use to assign a *function-type alias* to a function. 

I have found this most useful in Flutter development when I need to execute a function with a large signature name. For example:

This widget has a long `onPressed` signature for that member:
```dart
class HomePage extends StatelessWidget {
  HomePage(this.onPressed);
  
  // This is a long signature that can be reduced via typedef.
  final void Function(ViewModel, DateTime) onPressed;

  @override
  Widget build(BuildContext context) {...}
}
```

But we can keep it concise with `typedef`:

```dart
// Our new signature for this function.
typedef ViewModelCallback = void Function(ViewModel, DateTime);

class HomePage extends StatelessWidget {
  HomePage(this.onPressed);

  // The function member with a new signature.
  final ViewModelCallback onPressed;

  @override
  Widget build(BuildContext context) {...}
}
```

## Trick 5: Use an `extension` on `enum` to add more fuctionality

You've already seen an `extension` used in this list to add functionality, but try using an extension on an `enum` to give it this little bit of functionality that you need.

```dart
enum DayOfTheWeek {
  sunday,
  monday,
  tuesday,
  wednesday,
  thursday,
  friday,
  saturday,
}

extension DayOfTheWeekX on DayOfTheWeek {
  /// The shorthand or abbreviated string of this day of the week.
  String get abbreviation => _abbreviationMap[this]!;

  // a mapping of all the abbreviations
  static const _abbreviationMap = {
    DayOfTheWeek.sunday: 'Sun',
    DayOfTheWeek.monday: 'Mon',
    DayOfTheWeek.tuesday: 'Tue',
    DayOfTheWeek.wednesday: 'Wed',
    DayOfTheWeek.thursday: 'Thur',
    DayOfTheWeek.friday: 'Fri',
    DayOfTheWeek.saturday: 'Sat',
  };
}
```