Fix type issue with RestorableNumN (and its subclasses) (#72862)

* Fix type issue with restorableN values
diff --git a/packages/flutter/lib/src/widgets/restoration_properties.dart b/packages/flutter/lib/src/widgets/restoration_properties.dart
index 7e170f6..f065388 100644
--- a/packages/flutter/lib/src/widgets/restoration_properties.dart
+++ b/packages/flutter/lib/src/widgets/restoration_properties.dart
@@ -306,11 +306,11 @@
 /// See also:
 ///
 ///  * [RestorableNum] for the non-nullable version of this class.
-class RestorableNumN<T extends num?> extends _RestorablePrimitiveValueN<num?> {
+class RestorableNumN<T extends num?> extends _RestorablePrimitiveValueN<T> {
   /// Creates a [RestorableNumN].
   ///
   /// {@macro flutter.widgets.RestorableNum.constructor}
-  RestorableNumN(num? defaultValue) : super(defaultValue);
+  RestorableNumN(T defaultValue) : super(defaultValue);
 }
 
 /// A [RestorableProperty] that knows how to store and restore a [double]
@@ -321,7 +321,7 @@
 /// See also:
 ///
 ///  * [RestorableDouble] for the non-nullable version of this class.
-class RestorableDoubleN extends RestorableNumN<double> {
+class RestorableDoubleN extends RestorableNumN<double?> {
   /// Creates a [RestorableDoubleN].
   ///
   /// {@macro flutter.widgets.RestorableNum.constructor}
@@ -336,7 +336,7 @@
 /// See also:
 ///
 ///  * [RestorableInt] for the non-nullable version of this class.
-class RestorableIntN extends RestorableNumN<int> {
+class RestorableIntN extends RestorableNumN<int?> {
   /// Creates a [RestorableIntN].
   ///
   /// {@macro flutter.widgets.RestorableNum.constructor}
diff --git a/packages/flutter/test/widgets/restorable_property_test.dart b/packages/flutter/test/widgets/restorable_property_test.dart
index 028134a..3ecf452 100644
--- a/packages/flutter/test/widgets/restorable_property_test.dart
+++ b/packages/flutter/test/widgets/restorable_property_test.dart
@@ -13,7 +13,7 @@
     expect(() => RestorableInt(1).value, throwsAssertionError);
     expect(() => RestorableString('hello').value, throwsAssertionError);
     expect(() => RestorableBool(true).value, throwsAssertionError);
-    expect(() => RestorableNumN<num>(0).value, throwsAssertionError);
+    expect(() => RestorableNumN<num?>(0).value, throwsAssertionError);
     expect(() => RestorableDoubleN(1.0).value, throwsAssertionError);
     expect(() => RestorableIntN(1).value, throwsAssertionError);
     expect(() => RestorableStringN('hello').value, throwsAssertionError);
@@ -308,6 +308,43 @@
     });
     expect(state.objectValue.didUpdateValueCallCount, 1);
   });
+
+
+  testWidgets('RestorableN types are properly defined', (WidgetTester tester) async {
+    await tester.pumpWidget(const RootRestorationScope(
+      restorationId: 'root-child',
+      child: _RestorableWidget(),
+    ));
+
+    expect(find.text('hello world'), findsOneWidget);
+    final _RestorableWidgetState state = tester.state(find.byType(_RestorableWidget));
+    state.setProperties(() {
+      state.nullableIntValue.value = 24;
+      state.nullableDoubleValue.value = 1.5;
+    });
+
+    // The following types of asserts do not work. They pass even when the
+    // type of `value` is a `num` and not an `int` because `num` is a
+    // superclass of `int`. This test is intended to prevent a regression
+    // where RestorableIntN's value is of type `num?`, but it is passed into
+    // a function which requires an `int?` value. This resulted in Dart
+    // compile-time errors.
+    //
+    // expect(state.nullableIntValue.value, isA<int>());
+    // expect(state.nullableIntValue.value.runtimeType, int);
+
+    // A function that takes a nullable int value.
+    void takesInt(int? value) {}
+    // The following would result in a Dart compile-time error if `value` is
+    // a `num?` instead of an `int?`.
+    takesInt(state.nullableIntValue.value);
+
+    // A function that takes a nullable double value.
+    void takesDouble(double? value) {}
+    // The following would result in a Dart compile-time error if `value` is
+    // a `num?` instead of a `double?`.
+    takesDouble(state.nullableDoubleValue.value);
+  });
 }
 
 class _TestRestorableValue extends RestorableValue<Object?> {
@@ -348,7 +385,7 @@
   final RestorableInt intValue = RestorableInt(42);
   final RestorableString stringValue = RestorableString('hello world');
   final RestorableBool boolValue = RestorableBool(false);
-  final RestorableNumN<num> nullableNumValue = RestorableNumN<num>(null);
+  final RestorableNumN<num?> nullableNumValue = RestorableNumN<num?>(null);
   final RestorableDoubleN nullableDoubleValue = RestorableDoubleN(null);
   final RestorableIntN nullableIntValue = RestorableIntN(null);
   final RestorableStringN nullableStringValue = RestorableStringN(null);