Jul 24, 2021
Dart has so many cool features that make the language so much fun to use, many of which are unknown to newcomers. I created this series to help improve your Dart skills by introducing you to one great feature at a time, making Dart cooler to use, hence the name, Dart on Ice!
This series is written with null safety in mind.
Let’s start by taking a look at extension methods in Dart, as well as how to use them practically in your applications.
The extension keyword
Dart 2.7 introduced extension methods to the language. It allows you to add additional methods to any class. They are super helpful, especially for transformations on primitive Data like strings.
Let’s start with an example. Let’s say we wanted to check if a string is a URL or not.
There are better ways to validating a url, but this example should help convey the point.
This works great! But if we wanted to use this logic somewhere else, writing this repeatedly everywhere in the app would be far from ideal. So to solve this problem, we can create a global helper function that checks this for us.
Much better! Now you can reuse this code everywhere in your Flutter or Dart application. Still, Dart provides a much nicer way of handling this. Using extensions, we can write:
Writing extensions give us “second-class” access to an object, allowing us to add additional methods, getters, or setters to any object. In this case, we declare an extension StringExt
on String
, then add a new getter to the String object isUrl
. To refer to the object we are writing the extension for, we use the this
keyword.
Of course, you don’t have to use the this
keyword, but it’s much easier to explain it like this.
Now we can check if a string is a url like this:
Here’s another example of an extension on DateTime
.
This returns a new DateTime
with values for the day, month and year alone. In other words, it strips away the time from the date.
Running this example prints the following:
More Examples of Dart Extensions in Real World Applications
There’s so much you can do with Dart extensions in real-world applications. For example, if you’re a Cloud Firestore user, you can use them to manage to retrieve your collection and document references.
Now, if you wanted to retrieve the userCollection
, for example, you’d call firestore.userCollection
.
Here’s an example of a firebase app architected with extension methods.
Nullable types and Generics
Because nullable types and non-nullable types are different, an extension on String?
will not work for String
and vice-versa. Take a look at this example:
text.toDate
doesn’t work because the text
from getDateCreated
is nullable. Of course, if we’re to use the bang operator (!) or the null aware operator (?), this would compile.
Of course, you can also create extensions for nullable types.
Dart also allows you to create extensions for classes with type parameters. Therefore, this example is totally valid:
Dart even gives you the option of writing generic extensions. So you can create an extension with generic type parameters.
A Note on Imports
If you create an extension in one file and try to use it in another, you’d notice that you won’t be able to use it in another without importing it. Manually importing the file containing your extension can be annoying if it is deeply nested in your folder structure.
To solve this problem, give your extensions clear, memorable names, like StringExt
, NumExt
or UserExt
so you can automatically import them using their names in your IDE or text editor of choice.
Anonymous extensions
If you don’t give an extension a name, it becomes private, meaning that you can’t use it in other files.
This extension would only be available in the file it lives in. You can also do the same by adding an underscore (_) before the name.
Additional References
If you’d like to learn more about Dart extensions, be sure to look at the following resources.
Dart: Extension methods (Documentation)