2

Given some nullable type T?, how do I get the corresponding non-nullable one T ?

For example:

T? x<T extends int?>(T? value) => value;
Type g<T>(T Function(T) t) => T;
Type type = g(x);
print(type); // Prints "int?"

Now I want to get the non-nullable type. How do I create the function convert so that:

Type nonNullableType = convert(type);
print(nonNullableType); // Prints "int"
Marcelo Glasberg
  • 29,013
  • 23
  • 109
  • 133

3 Answers3

6

If you have an instance of T?, and you're trying to do something where the expected type is T, you can use use T! wherever dart is showing an error. It is not exactly a conversion from T? to T, its just a shortcut to do a null check.

Jishnu Vijayan
  • 103
  • 2
  • 7
3

If you have an instance of T?, I think you could do:

Type nonNullableTypeOf<T>(T? object) => T;

void main() {
  int x = 42;
  int? y;
  print(nonNullableTypeOf(x)); // Prints: int
  print(nonNullableTypeOf(y)); // Prints: int
}

If you have only T? itself (the Type object), then I'm not confident that there's much you can do since what you can do with Type objects is very limited. (And given those limitations, it's not clear that nonNullableTypeOf ultimately would be very useful either.)

A related question: How do I check whether a generic type is nullable in Dart NNBD?

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
  • 1
    Yes, but I really only have the Type `T?`, not an instance of `T?`. My use case at the moment is that I have a map where the non-nullable types are the keys, and I want to be able to convert the nullable one so that I can use this map. – Marcelo Glasberg Apr 24 '21 at 21:18
  • I think you should provide a concrete example of what you're actually trying to accomplish to avoid falling into the XY problem trap. There possibly are better ways to do what you want. – jamesdlin Apr 24 '21 at 21:44
  • I am just trying to translate legacy nullable code that works into non-nullable, and that map stopped working. It's not that I can't find better ways to do what I want, but I was just hoping for a fast fix. It seems there isn't. Thanks anyway! – Marcelo Glasberg Apr 24 '21 at 23:11
3

In general, you do not. There is no simple way to strip the ? of a type, or destructure types in other ways. (You also can't find the T of type you know is a List<T> at run--time)

If you have the type as a Type object, you can do nothing with it. Using Type object is almost never what you need.

If you have the type as a type parameter, then the type system don't actually know whether it's nullable. Example:

void foo<T>() { ... here T can be nullable or non-nullable ... }

Even if you test null is T to check that the type is actually nullable, the type system doesn't get any smarter, that's not one of the tests that it can derive type information from.

The only types you can improve on are variable types (or rather, the type of a single value currently stored in a variable). So, if you have T x = ...; and you do if (x != null) { ... x is not null here }, you can promote the variable to T&Object, but that's only an intermediate type to allow you to call members on the variable, it's not a real type that you can capture as a type variable or a variable type. It won't help you.

All in all, it can't be done. When you have the nullable type, it's too late, you need to capture it before adding the ?.

What problem are you actually trying to solve?

lrn
  • 64,680
  • 7
  • 105
  • 121
  • As I said in the other comment, I am just trying to translate legacy nullable code that works into non-nullable. It uses a map where the keys are types, and the values are some information related to their types. That's necessary because we can't use mirrors. Now I must be able to get that value for some type, nullable or not. It worked before nnbd, but now that map stopped working. Anyway... It would be nice if we could have some more intelligent types, even if we can't have the complete mirrors package. – Marcelo Glasberg Apr 26 '21 at 15:51
  • 1
    Sounds like your code is using `Type` objects. Since the only thing you can do with type objects is compare them for equality, you do need to use the exact same type as key every time. If you use type literals, always use the non-nullable version. If you use type parameters, you can make those non-nullable by doing `foo` and then using `T?` where you need the nullable version, instead of allowing people to pass `int?` as the value of `T`. – lrn Apr 27 '21 at 05:52