tezvyn:

Dart Generics: Type-Safe Containers and Reusable Code

AI-drafted, machine-checkedSource: dart.devadvanced

Generics let you define code that works with multiple types without sacrificing type safety. A `List<String>` is a list that only accepts strings. This is essential for collections.

WHY IT EXISTS: Generics solve the problem of writing code that operates on different data types without either duplicating the code for each type or losing type safety by using a general type like Object or dynamic.

THE MENTAL MODEL: Think of generics as creating a template for a class or function. The <T> is a placeholder for a "type" that will be specified later. When you declare a List<String>, you're telling the List template, "For this instance, everywhere you see your type placeholder, use String." This allows the compiler to enforce that only strings can be added to that list.

HOW IT WORKS: In Dart, you define a generic type by adding <...> after the class or function name. By convention, type variables are single letters like E, T, K, or V. List<E> is a generic class where E is the type parameter for the element type. When you instantiate it, like var names = <String>['Seth'];, you provide a type argument (String). The Dart compiler then uses this information to ensure type safety. An attempt to names.add(42); will result in a compile-time error.

WHEN TO USE IT: Use generics whenever you're creating a container or a utility that should work with a variety of types while remaining type-safe. This is most common with collections (List<T>, Map<K, V>). It's also key for reducing code duplication in functions that perform the same logic on different types. Properly using generics also helps the compiler produce better, more optimized code.

WHEN NOT TO USE IT: While powerful, generics are not always necessary. If a class or function is genuinely intended to work with only one specific, concrete type, adding generics can over-complicate the API. For example, a Customer class that holds a String name and int id does not need to be generic.

ONE CANONICAL EXAMPLE: The most common example is List<E>. If you have a list intended to hold only integers, you declare it as List<int>. var numbers = <int>[1, 2, 3]; numbers.add(4); // OK // numbers.add('five'); // Error: The argument type 'String' can't be assigned to the parameter type 'int'. Omitting the type parameter, var stuff = [];, creates a List<dynamic> by default, which loses the type safety benefit and can lead to runtime errors.

Read the original → dart.dev

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.