How to perform runtime type checking in Dart?
Asked Answered
S

11

229

Dart specification states:

Reified type information reflects the types of objects at runtime and may always be queried by dynamic typechecking constructs (the analogs of instanceOf, casts, typecase etc. in other languages).

Sounds great, but there is no instanceof-like operator. So how do we perform runtime type-checking in Dart? Is it possible at all?

Sense answered 10/10, 2011 at 16:39 Comment(0)
S
318

The instanceof-operator is called is in Dart. The spec isn't exactly friendly to a casual reader, so the best description right now seems to be http://www.dartlang.org/articles/optional-types/.

Here's an example:

class Foo { }

main() {
  var foo = new Foo();
  if (foo is Foo) {
    print("it's a foo!");
  }
}
Swayback answered 10/10, 2011 at 16:51 Comment(8)
Looks like there is no mention of is operator at all in the specification. It's better to refere to the grammar file in Dart sources: code.google.com/p/dart/source/browse/trunk/dart/language/…Sense
@Idolon, the is operator is defined on page 59 of the spec, section 10.30 'Type test'Soto
is and is! can be found in the Operators section of the Dart language tour.Boehmenist
new syntax is getTypeName(dynamic obj) => obj.runtimeType;Emlynne
Is there a way to use the runtimeType to check whether a particular named constructor was used?Keifer
The Dart Language Tour has sections on equality operators: dart.dev/guides/language/… and type operators: dart.dev/guides/language/language-tour#type-test-operatorsHobart
How to use this operator to check Maps because maps can have several types like <Type, type> etc?Goldofpleasure
Make sure you don't combine the two different methods here and end up with foo.runtimeType is String that screwed me up for a while.Sokol
K
78

Dart Object type has a runtimeType instance member (source is from dart-sdk v1.14, don't know if it was available earlier)

class Object {
  //...
  external Type get runtimeType;
}

Usage:

Object o = 'foo';
assert(o.runtimeType == String);
Kiss answered 11/3, 2016 at 21:31 Comment(10)
RuntimeType is only for debugging purposes and the application code shouldn't depend on it. It can be overridden by classes to return fake values and probably returns unusable values when transpiled to JSBeverle
Thanks for your remark, I'm pretty new to Dart, and I agree that runtimeType may be overriden by classes, although I can't think of a reason why they would. (external code can't set the value sinse it's a getter) Personally, I would stick to is and reflection.Kiss
It's fine this is mentioned here. It's not very obvious that runtimeType has these limitations.Beverle
Gunter, is it still the case that runtimeType should only be used for debugging purposes? I ask because there isn't any mention of this in the docs for Object, or elsewhere (that I could find).Spiniferous
@MattC yes, I was using runtimeType to generate HTML classes on the fly, it works with development build, but fails with release build, e.g. in my case result is minified:ed instead of columnMontalvo
@GünterZöchbauer comment is no longer true in Dart 2. It should be fine to use it now.Bearnard
@Bearnard I'm mot aware of any related changes. Why do you think my comment is obdolete?Beverle
@GünterZöchbauer I'm not expert on Dart 2 differences. I commented based on this discussion ibb.co/WcVJzhz ibb.co/zmgq168 Let me know what you think.Bearnard
I'm not sure why he thinks it's ok in Dart 2. Perhaps I missed something.Beverle
"is" repects class hierarchy. Comparing runtimeType must have a precise equality. Therefore, please use "is".Majorette
A
22

As others have mentioned, Dart's is operator is the equivalent of Javascript's instanceof operator. However, I haven't found a direct analogue of the typeof operator in Dart.

Thankfully the dart:mirrors reflection API has recently been added to the SDK, and is now available for download in the latest Editor+SDK package. Here's a short demo:

import 'dart:mirrors'; 

getTypeName(dynamic obj) {
  return reflect(obj).type.reflectedType.toString();
}

void main() {
  var val = "\"Dart is dynamically typed (with optional type annotations.)\"";
  if (val is String) {
    print("The value is a String, but I needed "
        "to check with an explicit condition.");
  }
  var typeName = getTypeName(val);
  print("\nThe mirrored type of the value is $typeName.");
}
Abri answered 30/8, 2012 at 14:1 Comment(4)
Is Dart a statically typed language?Miltonmilty
it is good solution but, we have error: Unsupported operation: dart:mirrors is no longer supported for web appsEmlynne
@Miltonmilty This answer was written for Ecma TC52. See dart.dev/faqAbri
Be aware that Flutter, if you're using that, disables reflection (because it breaks tree shaking).Philodendron
D
22

Simply use .runtimeType on the property like below,

print(unknownDataTypeProperty.runtimeType)
Duffey answered 8/11, 2020 at 13:7 Comment(0)
K
21

Exact type matching is done via runtimeType property. Checking if an instance or any of its parent types (in the inheritance chain) is of the given type is done via is operator:

class xxx {}

class yyy extends xxx {}

void main() {
  var y = yyy();
  
  print(y is xxx);
  print(y.runtimeType == xxx);
}

Returns:

true
false
Keeler answered 3/3, 2021 at 11:28 Comment(0)
S
20

There are two operators for type testing: E is T tests for E an instance of type T while E is! T tests for E not an instance of type T.

Note that E is Object is always true, and null is T is always false unless T===Object.

Soto answered 11/10, 2011 at 8:56 Comment(3)
Could you explain what is meant by by T===Object? Dart doesn't have the triple equals operator, but you chose to use it rather than double equals, so I assume the difference has significance.Spiniferous
@MattC That was written more than 7 years ago! I think what I meant was null is Object would be true but null is T false for any other type T. tbh though I haven't been near Dart for many years now so can't be certain.Soto
You save my day man! With this: var isAuthFailure = Failure is! AuthenticationFailure;Closefisted
F
15

Just to clarify a bit the difference between is and runtimeType. As someone said already (and this was tested with Dart V2+) the following code:

class Foo {
  @override
  Type get runtimeType => String;
}
main() {
  var foo = Foo();
  if (foo is Foo) {
    print("it's a foo!");
  }
  print("type is ${foo.runtimeType}");
  
}

will output:

it's a foo! 
type is String

Which is wrong. Now, I can't see the reason why one should do such a thing...

Ferdinand answered 10/10, 2011 at 16:39 Comment(0)
C
3

if(value is int ) Returns true if the type of the value is int, else if(value is! int )

Cause answered 28/10, 2022 at 8:14 Comment(0)
S
2

T is The type

   print( T.runtimeType)

enter image description here


enter image description here

Strobilaceous answered 21/2, 2022 at 17:10 Comment(0)
H
1

To check the type of a variable use runtimeType

void main() {
  int a = 10;
  print(a.runtimeType);
}

to check whether the type of a variable is the same as your expected use is or runtimeType

void main() {
  int a = 10;
  print(a.runtimeType == int); // true
  //or
  print(a is int); // true
}
Hypocaust answered 29/1, 2023 at 6:58 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Eyelid
O
1
  • .runtimeType property does an exact type match.
  • is keyword matches on parent class types and class extension types
    class Aaa {}

    class Bbb extends Aaa {}
    
    void main() {
      var x = Bbb();
      
      print(x is Aaa);                  // true
      print(x is Bbb);                  // true
      print(x.runtimeType == Aaa);      // false
      print(x.runtimeType == Bbb);      // true
      print(x.runtimeType);             // Bbb
      print(x.runtimeType.runtimeType); // _Type
      print(x.runtimeType.toString());  // Bbb
    }

Ostmark answered 22/12, 2023 at 0:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.