marcglasberg / fast_immutable_collections

Dart Package: Immutable lists, sets, maps, and multimaps, which are as fast as their native mutable counterparts. Extension methods and comparators for native Dart collections.
BSD 2-Clause "Simplified" License
218 stars 30 forks source link

Use of Fast Immutable Collections with Freezed results in dynamic types #51

Closed shtse8 closed 1 year ago

shtse8 commented 1 year ago

I'm using the fast_immutable_collections package with the freezed package in my Dart project. However, I noticed that when using IList or ISet with freezed, the generated code results in dynamic types.

For example, here's a simplified version of the code I'm using:

import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:freezed_annotation/freezed_annotation.dart';

part 'my_class.freezed.dart';

@freezed
abstract class MyClass with _$MyClass {
  const factory MyClass({
    @Default(IListConst([])) IList<int> numbers,
  }) = _MyClass;
}

When running freezed to generate the code, the generated class for _MyClass has dynamic types instead of IList<int>.

abstract class _MyClass implements MyClass {
  const factory _MyClass({
    dynamic numbers, // Should be IList<int>
  }) = _$_MyClass;
}

This results in issues when trying to use the numbers property in my code, as I need it to be of type IList<int>.

However, I noticed that freezed works well with other generic types such as List or Test.

I'm wondering if this is expected behavior or if there's something I'm missing. Is there a way to use IList or ISet with freezed and still have the generated code use the correct types?

Thanks for your help!

marcglasberg commented 1 year ago

I have never used freezed, so I would need someone to help me fix this. A PR is welcomed.

tjarvstrand commented 1 year ago

I use freezed together with FIC and I don't see thing behavior. I tried your snippet and this is my generated code:

// **************************************************************************
// FreezedGenerator
// **************************************************************************

T _$identity<T>(T value) => value;

final _privateConstructorUsedError = UnsupportedError(
    'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods');

/// @nodoc
mixin _$MyClass {
  IList<int> get numbers => throw _privateConstructorUsedError;

  @JsonKey(ignore: true)
  $MyClassCopyWith<MyClass> get copyWith => throw _privateConstructorUsedError;
}

/// @nodoc
abstract class $MyClassCopyWith<$Res> {
  factory $MyClassCopyWith(MyClass value, $Res Function(MyClass) then) =
      _$MyClassCopyWithImpl<$Res, MyClass>;
  @useResult
  $Res call({IList<int> numbers});
}

/// @nodoc
class _$MyClassCopyWithImpl<$Res, $Val extends MyClass>
    implements $MyClassCopyWith<$Res> {
  _$MyClassCopyWithImpl(this._value, this._then);

  // ignore: unused_field
  final $Val _value;
  // ignore: unused_field
  final $Res Function($Val) _then;

  @pragma('vm:prefer-inline')
  @override
  $Res call({
    Object? numbers = null,
  }) {
    return _then(_value.copyWith(
      numbers: null == numbers
          ? _value.numbers
          : numbers // ignore: cast_nullable_to_non_nullable
              as IList<int>,
    ) as $Val);
  }
}

/// @nodoc
abstract class _$$_MyClassCopyWith<$Res> implements $MyClassCopyWith<$Res> {
  factory _$$_MyClassCopyWith(
          _$_MyClass value, $Res Function(_$_MyClass) then) =
      __$$_MyClassCopyWithImpl<$Res>;
  @override
  @useResult
  $Res call({IList<int> numbers});
}

/// @nodoc
class __$$_MyClassCopyWithImpl<$Res>
    extends _$MyClassCopyWithImpl<$Res, _$_MyClass>
    implements _$$_MyClassCopyWith<$Res> {
  __$$_MyClassCopyWithImpl(_$_MyClass _value, $Res Function(_$_MyClass) _then)
      : super(_value, _then);

  @pragma('vm:prefer-inline')
  @override
  $Res call({
    Object? numbers = null,
  }) {
    return _then(_$_MyClass(
      numbers: null == numbers
          ? _value.numbers
          : numbers // ignore: cast_nullable_to_non_nullable
              as IList<int>,
    ));
  }
}

/// @nodoc

class _$_MyClass implements _MyClass {
  const _$_MyClass({this.numbers = const IListConst([])});

  @override
  @JsonKey()
  final IList<int> numbers;

  @override
  String toString() {
    return 'MyClass(numbers: $numbers)';
  }

  @override
  bool operator ==(dynamic other) {
    return identical(this, other) ||
        (other.runtimeType == runtimeType &&
            other is _$_MyClass &&
            const DeepCollectionEquality().equals(other.numbers, numbers));
  }

  @override
  int get hashCode =>
      Object.hash(runtimeType, const DeepCollectionEquality().hash(numbers));

  @JsonKey(ignore: true)
  @override
  @pragma('vm:prefer-inline')
  _$$_MyClassCopyWith<_$_MyClass> get copyWith =>
      __$$_MyClassCopyWithImpl<_$_MyClass>(this, _$identity);
}

abstract class _MyClass implements MyClass {
  const factory _MyClass({final IList<int> numbers}) = _$_MyClass;

  @override
  IList<int> get numbers;
  @override
  @JsonKey(ignore: true)
  _$$_MyClassCopyWith<_$_MyClass> get copyWith =>
      throw _privateConstructorUsedError;
}

Are you on the latest versions of freezed/FIC?

marcglasberg commented 1 year ago

@shtse8 Could you please try the current version 9.1.5 ?

shtse8 commented 1 year ago

@shtse8 Could you please try the current version 9.1.5 ?

I am confirmed it is working fine on the latest version.