In my flutter app, I have widgets like below:

Container(
  decoration: BoxDecoration(
    border: Border.all(
      color: Colors.red,
      width: 2,
      style: BorderStyle.solid,
    ),
  ),
  child: Text('Container 1'),
)
Container(
  decoration: BoxDecoration(
    border: Border(
      top: BorderSide(
        color: Colors.red,
        width: 2,
        style: BorderStyle.solid,
      ),
    ),
  ),
  child: Text('Container 2'),
)

Both use the same properties for their borders. So I was wondering if there's a spread-operator-like way of inserting the same properties for both widgets? Maybe like:

const borderBase = (
  color: Colors.red,
  width: 2,
  style: BorderStyle.solid,
)

Container(
  decoration: BoxDecoration(
    border: Border.all(
      ...borderBase,
    ),
  ),
  child: Text('Container 1'),
)

Container(
  decoration: BoxDecoration(
    border: Border(
      top: BorderSide(
        ...borderBase,
      ),
    ),
  ),
  child: Text('Container 2'),
)


Solution 1: Rémi Rousselet

There is no such thing.

A spread operator is in development, but it is only for lists, not classes (https://github.com/dart-lang/language/issues/47)


Solution 2: Daniel P

You can do something like this:

const BorderSide borderBase = BorderSide(
  color: Colors.red,
  width: 2,
  style: BorderStyle.solid,
);

Container(
  decoration: BoxDecoration(
    border: Border.all(
      color: borderBase.color,
      width: borderBase.width,
      style: borderBase.style,
    ),
  ),
  child: Text('Container 1'),
)

Container(
  decoration: BoxDecoration(
    border: Border(
      top: borderBase,
    ),
  ),
  child: Text('Container 2'),
)

Not the best but still some reuse.


Solution 3: bdi

Here is a dummy sample of my poor man's spread operator pattern:

I make a copy constructor for classes often re-created with slight modifications. It is extra work during definition, but it pays off at many locations when using these classes. The same pattern can be used on standard classes by subclassing -- just to connect to the specific question.

class Address {
    final String street;
    final String city;
    final String state;

    Address({this.street, this.city, this.state});

    Address.copy(Address copy, {
        String street,
        String city,
        String state,
    }) : this (
        street: street ?? copy.street,
        city: city ?? copy.city,
        state: state ?? copy.state,
    );
}

class User {
    final String firstName;
    final String lastName;
    final Address address;
    final String email;

    User({this.firstName, this.lastName, this.address, this.email});

    User.copy(User copy, {
        String firstName,
        String lastName,
        Address address,
        String email,
    }) : this (
        firstName: firstName ?? copy.firstName,
        lastName: lastName ?? copy.lastName,
        address: address ?? copy.address,
        email: email ?? copy.email,
    );
}

void workWithUsers(User user) {
    final userChangedEmail = User.copy(user, email: '[email protected]');
    final userMovedToAnotherStreet = User.copy(user, address: Address.copy(user.address, street: 'Newstreet'));
}


Solution 4: micimize

Now that dart has both the spread operator and class extensions, you could abuse both to add ...spread support to static methods. While I doubt this is a good idea, I made a working dartpad (gist) to demonstrate. The end result looks something like:

final Border spreadBorder = Border.fromSides([
  ...Border(
    left: BorderSide(color: Colors.pink),
    right: BorderSide(color: Colors.pinkAccent),
  ).sides,
  ...Border(
    top: BorderSide(color: Colors.blue),
    bottom: BorderSide(color: Colors.blueAccent),
  ).sides,
]).scale(5);

enum _Side { top, right, bottom, left }

extension SpreadBorder on Border {
  Iterable<MapEntry<_Side, BorderSide>> get sides {
    return () sync* {
      if (top != BorderSide.none) {
        yield MapEntry(_Side.top, top);
      }
      // ...other yields
    }();
  }

  static Border fromSides(Iterable<MapEntry<_Side, BorderSide>> parts) {
    BorderSide top, right, bottom, left;

    for (final borderPart in parts) {
      switch (borderPart.key) {
        case _Side.top:
          top = borderPart.value;
          break;
        // ... other cases
      }
    }
    return Border(
      top: top,
      right: right,
      bottom: bottom,
      left: left,
    );
  }
}


Solution 5: HongerTrollie

The spread operator will work on Maps e.g. Map<String, dynamic> so what worked for me was to convert the object to json which is Map<String, dynamic>, use the spread operator and then convert back to the object.

You can try something like this:

class Something {
  final String id;
  final String name;

  Something({required this.id, required this.name});

  factory Something.fromJson(Map<String, dynamic?> json){
    return Something(
      id: json['id'],
      name: json['name']
    );
  }

  Map<String, dynamic?> toJson() {
    return {
    'id': id,
    'name': name
    };
  }

}

final x = Something(id: 'abc', name: 'def');
final y = Something.fromJson({...x.toJson(), 'name': 'somethingElse'})

This might be very expensive to do, but if all you care about is using the spread operator, this should do the job.