message: feat(forms): Add a FormRecord type.
  As part of the typed forms RFC, we proposed the creation of a new FormRecord type, to support dynamic groups with homogenous values. This PR introduces FormRecord, as a subclass of FormGroup.
  PR Close
diff: import {FormBuilder, UntypedFormBuilder} from '../src/form_builder';
  import {AbstractControl, FormArray, FormControl, FormGroup, UntypedFormArray, UntypedFormControl, UntypedFormGroup, Validators} from '../src/forms';
  +import {FormRecord} from '../src/model/form_group';
  describe('Typed Class', () => {
  describe('FormControl', () => {
  @@ -636,6 +637,60 @@ describe('Typed Class', () => {
  });
  });
  + describe('FormRecord', () => {
  + it('supports inferred records', () => {
  + let c = new FormRecord({a: new FormControl(42, {initialValueIsDefault: true})});
  + {
  + type ValueType = Partial<{[key: string]: number}>;
  + let t: ValueType = c.value;
  + let t1 = c.value;
  + t1 = null as unknown as ValueType;
  + }
  + {
  + type RawValueType = {[key: string]: number};
  + let t: RawValueType = c.getRawValue();
  + let t1 = c.getRawValue();
  + t1 = null as unknown as RawValueType;
  + }
  + c.registerControl('c', new FormControl(42, {initialValueIsDefault: true}));
  + c.addControl('c', new FormControl(42, {initialValueIsDefault: true}));
  + c.setControl('c', new FormControl(42, {initialValueIsDefault: true}));
  + c.removeControl('c');
  + c.removeControl('missing');
  + c.contains('c');
  + c.contains('foo');
  + c.setValue({a: 42});
  + c.patchValue({c: 42});
  + c.reset({c: 42, d: 0});
  + });
  +
  + it('supports explicit records', () => {
  + let c = new FormRecord<FormControl<number>>(
  + {a: new FormControl(42, {initialValueIsDefault: true})});
  + {
  + type ValueType = Partial<{[key: string]: number}>;
  + let t: ValueType = c.value;
  + let t1 = c.value;
  + t1 = null as unknown as ValueType;
  + }
  + {
  + type RawValueType = {[key: string]: number};
  + let t: RawValueType = c.getRawValue();
  + let t1 = c.getRawValue();
  + t1 = null as unknown as RawValueType;
  + }
  + c.registerControl('c', new FormControl(42, {initialValueIsDefault: true}));
  + c.addControl('c', new FormControl(42, {initialValueIsDefault: true}));
  + c.setControl('c', new FormControl(42, {initialValueIsDefault: true}));
  + c.contains('c');
  + c.contains('foo');
  + c.setValue({a: 42, c: 0});
  + c.patchValue({c: 42});
  + c.reset({c: 42, d: 0});
  + c.removeControl('c');
  + });
  + });
  +
  describe('FormArray', () => {
  it('supports inferred arrays', () => {
  const c = new FormArray([new FormControl('', {initialValueIsDefault: true})]);
  