Is it possible to assign a type to a variable and then use that to create a type-based object, such as a List? My use case is that I have a Flutter widget using a particular data type to create a List for a FutureBuilder. If I could parameterise the type rather than hard-coding it then I could re-use the widget for multiple data types.
I have tried to do this in DartPad as follows:
void main() {
A a = A(int);
a.stuff();
}
class A {
A(Type type) {
_type = type;
}
late Type _type;
void stuff() {
print('$_type'); // prints out 'int'
List<_type> b = [];
}
}
If I comment out the line List<_type> b = []; then the code works and the output is int.
However, if I include the List<> line then I get the error "The name '_type' isn't a type so it can't be used as a type argument."
If have found next to nothing on the internet about this so think it might not be possible.
I have also had a look at the question on stack overflow here, which seems to be a similar question. This uses generics, which I know nothing about, and I couldn't make it work in my case. Is this a similar problem to mine and is it worth me doing some more exploration down this path?
My other idea was to pass a specific instance of the type that I want and then use runtimeType to get the type. I have tried this in Dart and it also gives an error.
void main() {
A a = A(1);
a.stuff();
}
class A {
A(this.value){}
dynamic value;
void stuff() {
print('${value.runtimeType}'); // prints out 'int'
List<value.runtimeType> b = [];
}
}
If I comment out the List<> line then the code outputs int.
However, with the list line uncommented, it gives the error "'type.runtimeType' can't be used as a type because 'type' doesn't refer to an import prefix."
Does anyone know if it possible to do what I want? Thanks.
Here is the full code for my use-case. I have commented the line that I would like to be able to parameterise somehow so that I can re-use the widget for different data sets with the same structure.
import 'package:drift/drift.dart' as drift;
import 'package:flutter/material.dart';
import 'package:frequent/database/tables.dart';
import 'package:frequent/maintain/change_record_widget.dart';
import 'package:frequent/maintain/change_record.dart';
class MaintainInstruments extends StatefulWidget {
MaintainInstruments({
Key? key,
required String title,
required MyDatabase database,
}) : super(key: key) {
_title = title;
_db = database;
}
late final String _title;
late final MyDatabase _db;
@override
State<MaintainInstruments> createState() => _MaintainInstrumentsState();
}
class _MaintainInstrumentsState extends State<MaintainInstruments> {
final double _width = 300;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
widget._title,
),
),
//
// Is it possible to parameterise the following statement so that I can
// re-use this widget for a variety of data types that follow the same
// format (id, name)?
//
body: FutureBuilder<List<InstrumentData>>(
future: _getInstruments(widget._db),
builder: (context, values) {
return Center(
child: Container(
decoration: BoxDecoration(
border: Border.all(),
// color: Colors.blueGrey,
borderRadius: const BorderRadius.all(Radius.circular(5)),
),
child: Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: [
TableRow(
children: [
TableCell(
child: SizedBox(
height: 300,
width: _width,
child: ListView.builder(
itemCount: values.hasData ? values.data!.length : 0,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(values.data![index].name),
tileColor: Colors.amber[200],
hoverColor: Colors.amber[400],
dense: true,
onTap: () {},
trailing: SizedBox(
width: _width * 0.2,
child: Row(
children: [
Expanded(
child: IconButton(
iconSize: 20,
icon: const Icon(Icons.edit),
onPressed: () {
showDialog<Record>(
context: context,
builder:
(BuildContext context) {
return ChangeRecord(
record: Record.instrument(
id: values
.data![index].id,
instrument: values
.data![index].name,
),
);
},
).then((value) {
setState(() {
_updateInstrument(
widget._db,
value!.id,
value.instrument);
});
});
},
),
),
Expanded(
child: IconButton(
iconSize: 20,
icon: const Icon(Icons.delete),
onPressed: () {
setState(() {
_deleteInstrument(widget._db,
values.data![index].id);
});
},
),
),
],
),
), // Just to track mouse over cards
),
);
},
),
),
),
],
),
],
),
),
);
},
),
);
}
}
Future<List<InstrumentData>> _getInstruments(MyDatabase db) async {
List<InstrumentData> values = await (db.select(db.instrument)
..orderBy([(t) => drift.OrderingTerm(expression: t.name)]))
.get();
return values;
}
void _deleteInstrument(MyDatabase db, int id) {
(db.delete(db.instrument)..where((tbl) => tbl.id.equals(id))).go();
}
_updateInstrument(MyDatabase db, int id, String value) {
(db.update(db.instrument)..where((tbl) => tbl.id.equals(id)))
.write(InstrumentCompanion(name: drift.Value(value)));
}
List<Type>. inside that bracket is atype annotationnot an instance.