From 2e6c806cc60643baeb35c68fad531ea1962f51ab Mon Sep 17 00:00:00 2001 From: leonsenft Date: Wed, 5 Sep 2018 15:47:19 -0700 Subject: [PATCH] feat(Generics): add support for generic components and directives Closes https://github.com/dart-lang/angular/issues/68. Closes https://github.com/dart-lang/angular/issues/1530. PiperOrigin-RevId: 211713269 --- _goldens/test/_files/directives/generics.dart | 2 - .../directives/generics.template.golden | 1 - _tests/test/core/generics/generics_test.dart | 2 - angular/CHANGELOG.md | 40 +++++++++++++++++++ angular/build.yaml | 2 - angular/lib/src/core/metadata.dart | 3 +- .../test/analyzer/view/typed_reader_test.dart | 11 ----- 7 files changed, 41 insertions(+), 20 deletions(-) diff --git a/_goldens/test/_files/directives/generics.dart b/_goldens/test/_files/directives/generics.dart index 7318afc670..7fb124b3c9 100644 --- a/_goldens/test/_files/directives/generics.dart +++ b/_goldens/test/_files/directives/generics.dart @@ -1,6 +1,4 @@ import 'package:angular/angular.dart'; -// TODO(leonsenft): remove when `Typed` is exported publicly. -import 'package:angular/src/core/metadata/typed.dart'; /// A component with no generic type parameters. @Component( diff --git a/_goldens/test/_files/directives/generics.template.golden b/_goldens/test/_files/directives/generics.template.golden index b2a99c2f7e..7398922cd3 100644 --- a/_goldens/test/_files/directives/generics.template.golden +++ b/_goldens/test/_files/directives/generics.template.golden @@ -6,7 +6,6 @@ import 'generics.dart'; export 'generics.dart'; import 'package:angular/angular.dart'; -import 'package:angular/src/core/metadata/typed.dart'; import 'package:angular/src/di/reflector.dart' as _ngRef; import 'package:angular/angular.template.dart' as _ref0; import 'package:angular/src/core/linker/app_view.dart'; diff --git a/_tests/test/core/generics/generics_test.dart b/_tests/test/core/generics/generics_test.dart index cca2d4feca..5ee9ac309e 100644 --- a/_tests/test/core/generics/generics_test.dart +++ b/_tests/test/core/generics/generics_test.dart @@ -2,8 +2,6 @@ import 'dart:async'; import 'package:angular/angular.dart'; -// TODO(https://github.com/dart-lang/angular/issues/1530): -import 'package:angular/src/core/metadata/typed.dart'; import 'package:angular_test/angular_test.dart'; import 'package:test/test.dart'; diff --git a/angular/CHANGELOG.md b/angular/CHANGELOG.md index 06d32a8585..d05dc3202d 100644 --- a/angular/CHANGELOG.md +++ b/angular/CHANGELOG.md @@ -1,3 +1,43 @@ +### New features + +* Added support for generic components and directives. + + Type arguments can now be specified for any generic components and + directives via `Typed` instances passed to the `Component` annotation's + `directiveTypes` parameter. + + ```dart + @Component( + selector: 'generic', + template: '{{value}}', + ) + class GenericComponent { + @Input() + T value; + } + + @Component( + selector: 'example', + template: ''' + + ''', + directives: [ + GenericComponent, + ], + directiveTypes: [ + Typed>(), + ], + ) + class ExampleComponent { + var value = 'Hello generics!'; + } + ``` + + The `Typed` class also has support for typing specific component and + directive instances by `#`-reference, and flowing generic type parameters + from the annotated component as type arguments to its children. See its + documentation for details. + ### Bug fixes * [#1538][]: A compile-time error is reported if the `@deferred` template diff --git a/angular/build.yaml b/angular/build.yaml index 32204a565d..915adf9f88 100644 --- a/angular/build.yaml +++ b/angular/build.yaml @@ -6,8 +6,6 @@ targets: exclude: - "lib/builder.dart" - "lib/src/compiler/**" - # TODO(https://github.com/dart-lang/angular/issues/1530) - - "lib/src/core/metadata/typed.dart" - "lib/src/source_gen/**" builders: diff --git a/angular/lib/src/core/metadata.dart b/angular/lib/src/core/metadata.dart index 1af0541c04..11e9dd16e0 100644 --- a/angular/lib/src/core/metadata.dart +++ b/angular/lib/src/core/metadata.dart @@ -17,8 +17,7 @@ export 'metadata/lifecycle_hooks.dart' OnDestroy, OnInit, DoCheck; -// TODO(leonsenft): export when support for generics is complete. -// export 'metadata/typed.dart'; +export 'metadata/typed.dart'; export 'metadata/view.dart'; export 'metadata/visibility.dart'; diff --git a/angular_compiler/test/analyzer/view/typed_reader_test.dart b/angular_compiler/test/analyzer/view/typed_reader_test.dart index 14d2b32a1e..0c500cf95e 100644 --- a/angular_compiler/test/analyzer/view/typed_reader_test.dart +++ b/angular_compiler/test/analyzer/view/typed_reader_test.dart @@ -9,14 +9,9 @@ import '../../src/compile.dart'; import '../../src/resolve.dart'; const testImport = 'asset:test_lib/lib/test_lib.dart'; -// TODO(leonsenft): remove when `Typed` is exported publicly. -final typedImport = - angular.replaceFirst('angular.dart', 'src/core/metadata/typed.dart'); Future parse(String source) async { final amendedSource = ''' - import "$typedImport"; - @Component() class GenericComponent {} @@ -223,7 +218,6 @@ void main() { test('if a concrete type is used as a type argument of "Typed"', () async { await compilesExpecting( ''' - import '$typedImport'; @Directive() class ConcreteDirective {} const typed = Typed(); @@ -243,7 +237,6 @@ void main() { test('if a non-existent type parameter is flowed', () async { await compilesExpecting( ''' - import '$typedImport'; @Component() class GenericComponent {} const typed = Typed.of([#X]); @@ -263,7 +256,6 @@ void main() { test("if a type argument isn't a supported type", () async { await compilesExpecting( ''' - import '$typedImport'; @Component() class GenericComponent {} const typed = Typed.of([12]); @@ -283,7 +275,6 @@ void main() { test('if "Typed.on" is specified anywhere other than the root', () async { await compilesExpecting( ''' - import '$typedImport'; @Component() class GenericComponent {} const typed = Typed.of([ @@ -305,7 +296,6 @@ void main() { test('if a directive with bounded type parameters is typed', () async { await compilesExpecting( ''' - import '$typedImport'; @Component() class GenericComponent {} const typed = Typed>(); @@ -324,7 +314,6 @@ void main() { test('if "Typed" isn\'t applied to a directive', () async { await compilesExpecting( ''' - import '$typedImport'; const typed = Typed>(); @typed