为 material-dropdown-select 明确指定类型而不是动态

Explicitly specify type for material-dropdown-select instead of dynamic

任务

在 AngularDart 中,我想通过 material-dropdown-select 选择多个 Foo 对象,并以反应形式存储选定的值。

我的做法

    import 'package:angular/angular.dart';
    import 'package:angular_components/angular_components.dart';
    import 'package:angular_forms/angular_forms.dart';

    @Component(
      selector: 'my-app',
      template: '''
        <form [ngFormModel]="form">
          <material-dropdown-select 
            multi 
            ngControl="control1"
            [options]="options"
            [itemRenderer]="renderer"
          >
          </material-dropdown-select>
        </form>
      ''',
      directives: [
        formDirectives,
        MaterialDropdownSelectComponent,
        MultiDropdownSelectValueAccessor,
      ],
      providers: [
        materialProviders,
      ],
    )
    class AppComponent {
      var options = SelectionOptions.fromList([Foo(50, 'op1'), Foo(51, 'op2'), Foo(52, 'op3')]);
      var form;

      AppComponent() {
        form = ControlGroup({
          'control1': Control<List<Foo>>(<Foo>[]),
        });
      }

      String renderer(Foo entry) => '${entry.id}: ${entry.title}';
    }

    class Foo {
      int id;
      String title;

      Foo(this.id, this.title);
    }

问题

由于模板代码出现异常,无法应用我的自定义渲染器:

EXCEPTION: Expected a value of type '(dynamic) => String', but got one of type '(Foo) => String'

dynamic从哪里出现的?我认为值访问器将从 options 中获取 Foo 类型!如果没有该渲染器,组件会出现,但选择任何项目都会抛出下一个:

Error: Type 'List<dynamic>' should be 'List<Foo>' to implement expected type 'List<Foo>'.

它从 material_dropdown_material_accessor.dart 文件中抛出,MultiDropdownSelectValueAccessor class:

    @override
    void registerOnChange(callback) {
      selectionChangesSub = selectionModel.selectionChanges.listen((_) {
        callback(selectionModel.selectedValues?.toList());
      });
    }

再一次 - dynamic 出现在哪里?将 material 下拉菜单与自定义类型一起使用是真的吗?

我想 MultiDropdownSelectValueAccessor 实现了 ControlValueAccessor<List<dynamic>>。可能您必须实现自己的值访问器,例如:

@Directive(
  selector : 'you-must-set-correct-selector-here`
)
class FooMultiDropdownSelectValueAccessor implements ControlValueAccessor<List<Foo>> {
  ...
}

选择器可以引入一些属性,例如[list-type=foo]

根本原因

问题在于 MaterialDropdownSelectComponent<T>MultiDropdownSelectValueAccessor<T> 是通用指令 T 默认为 dynamic

解决方案

有一个实验性的 AngularDart 功能 — directiveTypes。它允许为组件模板中的任何指令指定通用类型。在我的例子中,缺少的行如下:

    @Component(
        ...
        directiveTypes: [
            Typed<MaterialDropdownSelectComponent<Foo>>(),
            Typed<MultiDropdownSelectValueAccessor<Foo>>(),
        ],
    )
    class AppComponent {
        ...
    }

我在 GitHub issue. It's curious what TypeScript users do for working around that 上偶然发现了它。