Используйте Spread Operator на объекте с типом Safety в Dart - PullRequest
2 голосов
/ 06 апреля 2020

Я хотел бы использовать оператор Spread (...) для данных ключ-значение с типом безопасности. В TypeScript я достиг бы этого с помощью интерфейсов, но я не мог найти способ сделать это в дротике.

Неудачный подход 1: Использовать классы

class Foo {
  int aNumber;
  String aString;
}

Foo a = Foo();
Foo b = { ...a, 'aString': 'ipsum' }; // This literal must be either a map or a set.

Неудачный подход 2: Использование карт

Map<String, dynamic> a = { 'aNumber': 2, 'aString': 'lorem' };
Map<String, dynamic> b = { ...a, 'aString': 'ipsum' }; // No error, but also no type safety.

Примечание. В этих подходах b не должно быть списком.

TypeScript Пример того, что мне нужно

interface Foo {
  aNumber: number;
  aString: string;
}
const a: Foo = { aNumber: 2, aString: 'lorem' };
const b: Foo = { ...a, aString: 'ipsum' }; // Has all the props of 'a' and overrides 'aString' to 'ipsum'.

1 Ответ

3 голосов
/ 06 апреля 2020

Вы можете достичь этого при первом подходе, но у вас есть две проблемы с фрагментом:

Сначала проверьте, что оператор распространения реализован в итерируемом, поэтому строку Foo a = Foo(); следует заменить на несколько итерируемых список, например.

Вторая проблема, ошибка компиляции на Foo b = { ...a };, заключается в том, что Dart использует {} как для наборов, так и для карт, поэтому вы должны указать тип, добавив один или два параметра типа в <>.

Проверьте этот пример:

  var a = <Foo>[];
  var b = <String>[];  
  var c = <Foo>{...a}; // works, a is Foo list
  var d = <Foo>{...b}; // compile time error, 'String' can't be assigned to the set type 'Foo'.

Поскольку мы используем только 1 аргумент в var d = <Foo>{...b}; Дарт знает, что нам нужен набор.

ОБНОВЛЕНИЕ:

Для этого случая вы не можете использовать оператор спреда. Оператор Spread был введен для облегчения работы с коллекциями, а коллекции имеют тип, заданный параметрами generics. Поэтому, если ваш класс не реализует Iterable, вы не можете вызвать ... для данного экземпляра. Вы получите ошибку времени компиляции:

Spread elements in list or set literals must implement 'Iterable'

С другой стороны, как вы упоминаете, второй подход «не дает вам» безопасности типов, потому что вы используете Dynami c. И также ТОЛЬКО компилировать, потому что вы объявляете Map<String, dynamic> a = { 'aNumber': 2, 'aString': 'lorem' };, который является картой и реализует Iterable (вы можете использовать ... a).

Для вашей текущей проблемы вам нужно найти другое решение, возможно, пользовательское функция класса Foo, которая возвращает Map и заботится о типах, а затем использует оператор распространения на этой карте.

Надеюсь, это поможет!

...