void foo<T extends num, String> (T t) {
if (t is String) {
String s = t; // Error
}
}
A value of type 'T' can't be assigned to a variable of type 'String'.
CodePudding user response:
You won't be able to do this with base Dart as your generic type T
can only extends one class.
The only way I would see such a behavior feasible would be by using a 3rd party packages such as dartz with its Either
type.
Example
void foo<T extends num>(Either<T, String> t) {
final String s;
if (t.isRight()) {
s = (t as Right<T, String>).value;
} else {
s = (t as Left<T, String>).value.toStringAsFixed(3);
}
print(s);
}
foo(Left(1.0)); // prints '1.000'
foo<int>(Right('bar')); // prints 'bar'
CodePudding user response:
There is no syntax to specify that a generic type implement multiple interfaces, so there is no way for this to work with compile-time checks.
Furthermore, your particular example can't work because num
and String
cannot be extended nor implemented, so it's impossible to have a type that implements both.
If we change your example, which relies on a runtime check, to use two custom types, it still won't work:
class C1 {}
class C2 {
void f() => print('C2.f');
}
class C3 implements C1, C2 {
@override
void f() => print('C3.f');
}
void foo<T extends C1>(T t) {
if (t is C2) {
t.f(); // 'f' isn't defined for the type <unknown>
}
}
See https://github.com/dart-lang/language/issues/2047: t
isn't related to C2
, so the is C2
check unfortunately will not automatically promote it to C2
. You instead can use a runtime cast:
void foo<T extends C1>(T t) {
if (t is C2) {
(t as C2).f();
}
}
or upcast to Object
/dynamic
first:
void foo<T extends C1>(T t) {
Object t0 = t;
if (t0 is C2) {
t0.f();
}
}
But really you should just use T extends C3
if possible.