Что такое тип dynamic в Dart и когда его стоит использовать?

«Что такое тип dynamic в Dart и когда его стоит использовать?» — вопрос из категории Dart Core, который задают на 70% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

dynamic — это специальный тип в Dart, который отключает статическую проверку типов для переменной. Компилятор разрешает переменной типа dynamic содержать значение любого типа, а проверка корректности операций откладывается до времени выполнения (runtime).

Ключевые отличия:

  • dynamic vs Object: Оба могут хранить любое значение. Но с Object компилятор запрещает выполнять произвольные операции (например, вызывать методы) без явного приведения типа (as). С dynamic компилятор разрешает любые операции, а проверка произойдет в рантайме.

    Object obj = 'строка';
    // print(obj.length); // Ошибка компиляции: The getter 'length' isn't defined for 'Object'.
    print((obj as String).length); // Нужно явное приведение.
    
    dynamic dyn = 'строка';
    print(dyn.length); // Компиляция проходит, в runtime вызовется .length у String.
    dyn = 42;
    print(dyn.length); // Runtime ошибка: NoSuchMethodError (у int нет .length).
  • dynamic vs var: var — это синтаксический сахар, тип переменной выводится компилятором один раз при инициализации и далее не меняется. dynamic — это явный тип, который разрешает менять тип значения.

    var inferred = 'hello'; // Тип выведен как String.
    // inferred = 42; // Ошибка компиляции: A value of type 'int' can't be assigned.
    
    dynamic explicit = 'hello'; // Тип dynamic.
    explicit = 42; // OK.

Когда использование dynamic оправдано:

  1. Работа с JSON или внешними API со слабой типизацией: При десериализации данных неизвестной структуры, пока они не будут приведены к конкретным моделям.
    Map<String, dynamic> json = jsonDecode(response.body);
    String name = json['user']['name']; // Доступ к полям возможен, тип проверяется в runtime.
  2. Вызов методов через рефлексию (dart:mirrors) или при работе с dart:js для JavaScript-интеропа.
  3. В прототипах или скриптах, где скорость написания кода важнее его безопасности.

Рекомендация: Следует минимизировать использование dynamic в production-коде Flutter-приложений. Это ослабляет помощь инструментов (автодополнение, статический анализ) и увеличивает риск runtime-ошибок (NoSuchMethodError). Всегда предпочитайте строгую типизацию. Если структура данных известна, используйте модели с кодогенерацией (json_serializable, freezed). Если тип может быть одним из нескольких — используйте union-типы или классы-обертки.