Generalized type aliases / typedefs in Dart

You can view the feature specification for Generalized type alisases for the full design document.

I want to preface this by pointing out that Dart used to only support typedefs for functions. The new generalized feature supports typedefs for any type.

typedef JsonMap = Map<String, dynamic>;

JsonMap parseJsonMap(String input) => json.decode(input) as JsonMap;

This is especially useful when you have multiple generic types (type parameters) that cause long type names that are tedious to type, for example Map<ScaffoldFeatureController<SnackBar, SnackBarClosedReason>, SnackBar>. This can now be simplified using a type alias:

typedef ScaffoldSnackBarMap = Map<ScaffoldFeatureController<SnackBar, SnackBarClosedReason>, SnackBar>;

Syntax

If not clear from the above examples, this is the syntax for type alisases / typedefs:

'typedef' identifier typeParameters? '=' type ';'

This means that you always need to start with the typedef keyword followed by your desired identifier, e.g. FooTypeDef. After that, you can add type parameters, e.g. Foo<K, V>. The last step is adding the = symbol followed by the actual type you want to create an alias for. This can be any type, i.e. a class, primitive type, function type, or w/e. Do not forget the ; at the end ;)

// Type parameters / generic types in typedef.
typedef Foo<K, V> = Map<K, V>;

// Type alias for regular types.
typedef Bar = Widget;
// As well as primitive types.
typedef Baz = int;

// Function types are also supported.
typedef FooFunction<T, R> = R Function(T param);

Deprecating names

Additionally, you can use typedefs for any class names. Say you want to rename your class from Provider to Pod because you think the former is too verbose. If you are maintaining a package, this would be a breaking change. With the new generalized type aliases, you can simply rename your class and create a type alias that you deprecate:

class NewClassName<T> {}

@Deprecated("Use NewClassName instead")
typedef OldClassName<T> = NewClassName<T>;

Note that this example and the one above are taken from the proposed CHANGELOG entry for the feature.

How to use them

The feature will be shipped by default with Dart 2.13 but is currently still experimental. I will cover how to use it in both ways; the experimental method can be removed later on.

Dart 2.13

As I mentioned previously, the feature will be enabled by default starting with Dart 2.13. If you currently have Dart 2.13 installed already (you can use dart --version to check it for example), you can use this method. Otherwise, you should refer to the Experimental support section below.

In your pubspec.yaml, you need to define the lower bound on your Dart SDK constraint to be greater than or equal to 2.13.0:

environment:
  dart: '>=2.13.0 <3.0.0'

Experimental support

In your Flutter project (or any other Dart project), you currently need to enable them as an experiment. It means that they are hidden behind a feature flag.


Experimental Dart features can be configured using analysis_options.yaml. You can simply create an analysis_options.yaml file in the root of your project directory and add the following lines:

analyzer:
  enable-experiment:
    - nonfunction-type-aliases

Now, you need to also enable the experiment when you run (or build) your app:

flutter run --enable-experiment=nonfunction-type-aliases

To make sure that you can use this feature, use the master channel (flutter channel master when using Flutter).

Post a Comment

Previous Post Next Post

Subscribe Us


Get tutorials, Flutter news and other exclusive content delivered to your inbox. Join 1000+ growth-oriented Flutter developers subscribed to the newsletter

100% value, 0% spam. Unsubscribe anytime