# Data Types

Course: [Dart](https://www.devtutorials.ai/learn/dart) · Section: Dart Foundations
Source: https://www.devtutorials.ai/learn/dart/foundations/data-types

> The basic Dart types (int, double, num, String, bool, dynamic, Object, Null, Never), how Dart infers types, and how to check, convert, parse and cast values.

## What Is a Data Type?

**Data type** = the kind of value a variable holds.

For example:

- `13` is a whole number
- `1.52` is a decimal number
- `'Asha'` is text
- `true` is a yes-or-no answer

Each kind has its own name in Dart, like `int` or `String`.
The type decides what you can do with the value.

**Simple lesson:** every value in Dart has a type, and the type says what kind of value it is.

### A Real-World Example

Think of the school lab cupboard.

- Liquids go in **bottles**.
- Powders go in **jars**.
- Long rods go in **boxes**.
- Nobody pours water into a box, because it would leak.

Dart's types are those containers. An `int` variable holds whole numbers, and Dart will not let you pour text into it.

Every **Run** box on this page runs on the course's Dart runner in your browser.

Some boxes fail on purpose, to show a real type error.

## What You Will Learn

In this lesson, you will learn:

1. Why types matter, and the number, text and true/false types.
2. The special types: dynamic, Object, Null and Never.
3. How Dart infers types with var and final.
4. How to check a type with is and runtimeType.
5. How to convert text to numbers and back, and how to cast safely.

## Why Data Types Matter

### Strong Typing

**Strongly typed** = every variable has a type, and Dart checks it.

- You can write the type: `int age = 13;`
- Or let Dart work it out: `var age = 13;` (see below)
- Either way, `age` is an `int` and stays an `int`.

### Type Safety

**Type safety** = Dart stops you from using a value of the wrong type.

Run this. Text is put into a number box:

```dart runnable expect-error title="Text cannot go into an int"
void main() {
  int age = 'thirteen';
  print(age);
}
```

Dart says: `A value of type 'String' can't be assigned to a variable of type 'int'.`

- The mistake is found **before** the program runs.
- So it never reaches a user's phone.

**Simple lesson:** Dart checks types early, so many mistakes never reach the running program.

## Numeric Types

### int

**`int`** = a whole number, with no decimal point.

- Examples: `13`, `0`, `-5`, `2026`
- Use it for counts: students, marks, roll numbers, years.

### double

**`double`** = a number with a decimal point.

- Examples: `1.52`, `99.5`, `-0.25`
- Use it for measurements: height, price, temperature, percentage.

### num

**`num`** = any number, either an `int` or a `double`.

- Use it when a value could be either kind.
- `int` and `double` are both kinds of `num`.

```dart runnable title="int, double and num"
void main() {
  int students = 450;
  int temperature = -3;
  double height = 1.52;
  double price = 99.5;
  num anyNumber = 7;
  anyNumber = 2.5;

  print('Students: $students');
  print('Temperature: $temperature');
  print('Height: $height m');
  print('Price: ₹$price');
  print('Any number: $anyNumber');
}
```

`anyNumber` started as `7` and became `2.5`. A `num` box accepts both kinds.

### A double Always Shows Its Decimal Point

A `double` with a whole value still prints with `.0`:

```dart
double fee = 50;
print(fee);
```

The output is `50.0`, not `50`. Dart remembers it is a decimal number.

In real Dart, a whole-number `double` always prints with `.0`.

In this course's runner, it may print without the `.0`. The examples on these pages avoid that case.

**Simple lesson:** `int` is for whole numbers, `double` is for decimals, and `num` accepts both.

## String Type

**`String`** = text: letters, digits, spaces and symbols, inside quotes.

**String literal** = text written straight into your code, like `'Asha'`.

- Single quotes: `'Green Valley'`
- Double quotes: `"Green Valley"`
- Both mean the same. Most Dart code uses single quotes.

```dart runnable title="Strings"
void main() {
  String name = 'Kavya';
  String city = "Chennai";
  String rollNumber = '0021';
  print('$name lives in $city.');
  print('Roll number: $rollNumber');
}
```

`'0021'` is text, not a number. It keeps its zeros because it is a `String`.

You will learn much more in **Strings**.

**Simple lesson:** anything inside quotes is a `String`, even if it looks like a number.

## Boolean Type

**`bool`** = a value that is either `true` or `false`.

- `true` = yes.
- `false` = no.
- Write them in small letters, without quotes.

```dart runnable title="true or false"
void main() {
  bool isPresent = true;
  bool hasPaidFees = false;
  bool passed = 72 >= 35;
  print('Present: $isPresent');
  print('Fees paid: $hasPaidFees');
  print('Passed: $passed');
}
```

`72 >= 35` asks a question. The answer, `true`, is stored in `passed`.

A good `bool` name sounds like a question: `isPresent`, `hasPaidFees`, `canVote`.

**Simple lesson:** `bool` holds yes or no, and it decides what a program does next.

## Sort the Values by Type

Watch the quotes:

- **With quotes**, a value is always a `String`.
- **Without quotes**, `42` is an `int` and `true` is a `bool`.

## Special Types

### dynamic

**`dynamic`** = a type that turns off Dart's checking. The value can be anything, and it can change type.

**Dynamic typing** = the type is only known while the program runs.

```dart runnable title="A dynamic variable changes type"
void main() {
  dynamic box = 5;
  print('$box is a ${box.runtimeType}');
  box = 'five';
  print('$box is a ${box.runtimeType}');
  box = true;
  print('$box is a ${box.runtimeType}');
}
```

`runtimeType` tells you the type of the value right now. You will use it again below.

When to use `dynamic`:

- **Rarely.** Usually for data whose shape you do not know yet, like some JSON from a server (see **File Handling**).
- **Not** to avoid thinking about types. Dart stops warning you, so mistakes reach the running program.

### Null

**`null`** = no value at all, an empty box.

```dart runnable title="A variable that holds nothing"
void main() {
  String? nickname;
  print(nickname);
  nickname = 'Chotu';
  print(nickname);
}
```

- `String?` = a String, **or** null.
- A variable with `?` and no value starts as `null`.
- A plain `String` can **never** be null. Dart checks this.

You will learn this properly in **Null Safety**.

### Never

**`Never`** = a type with no values. A function that returns `Never` never finishes normally.

- Most beginners never write it.
- You may see it in error messages or library code.

**Simple lesson:** avoid `dynamic`, use `?` when a value may be missing, and leave `Never` to libraries.

## Choosing the Right Type

| The value is... | Use | Example |
|---|---|---|
| A count | `int` | `int students = 450;` |
| A measurement or money | `double` | `double height = 1.52;` |
| Text, or digits you never do maths on | `String` | `String phone = '9876543210';` |
| Yes or no | `bool` | `bool isPresent = true;` |
| Maybe missing | add `?` | `String? nickname;` |

**Easy way to remember**

Ask: "Will I do maths with it?"

- Yes, whole numbers: `int`.
- Yes, decimals: `double`.
- No, like a phone number or PIN code: `String`.

**Simple lesson:** pick the type that matches what the value means, not just what it looks like.

## What Is Type Inference?

**Type inference** = Dart works out the type of a variable from its first value.

For example:

- `var age = 13;` makes `age` an `int`
- `var height = 1.52;` makes `height` a `double`
- `var name = 'Asha';` makes `name` a `String`

You did not write the type, but Dart knows it, and it checks it like any other type.

**Simple lesson:** with `var` or `final`, Dart reads the value and picks the type for you.

### A Real-World Example

A school form asks for marks in a text box.

- What you type, like `85`, arrives as **text**: `'85'`.
- You cannot add text like numbers. `'85'` and `'90'` would just join into `'8590'`.
- So the program first **converts** the text into the number `85`.

This lesson teaches both ideas: how Dart knows types, and how to change one type into another.

Some boxes use the **Input** box on the right. Change the input and press **Run** again.

## Type Inference with var and final

```dart runnable title="Dart picks the types"
void main() {
  var students = 450;
  var fee = 1250.5;
  var school = 'Green Valley';
  final isOpen = true;

  print(students.runtimeType);
  print(fee.runtimeType);
  print(school.runtimeType);
  print(isOpen.runtimeType);
}
```

- `var` and `final` both use inference.
- The type is fixed after the first value.

### The Type Stays Fixed

Inference does **not** mean "any type". Run this:

```dart runnable expect-error title="An inferred type cannot change"
void main() {
  var marks = 90;
  marks = 'ninety';
  print(marks);
}
```

Dart says: `A value of type 'String' can't be assigned to a variable of type 'int'.`

`marks` became an `int` on line 2, and it stays an `int`.

**Simple lesson:** inference picks the type once, and Dart keeps checking it after that.

## Explicit Types vs Type Inference

**Explicit type** = you write the type yourself: `int age = 13;`

Write the type yourself when:

- the variable starts **without a value**: `int total;`
- you want a **wider type** than the value: `num price = 10;`
- the value does not make the type **obvious**

**Simple lesson:** let Dart infer obvious types, and write the type when it helps the reader.

## Type Checking

**Type checking** = making sure each value has the right type.

Dart does it at two times:

- **Compile-time checking** = before the program runs. Dart reads your code and stops on type mistakes.
- **Runtime checking** = while the program runs. You ask about a value with `is` or `runtimeType`.

### The is Operator

**`is`** = asks "is this value of that type?" The answer is `true` or `false`.

**`is!`** = the opposite: "is it NOT of that type?"

```dart runnable title="Asking about types with is"
void main() {
  var answer = 42;
  print(answer is int);
  print(answer is num);
  print(answer is String);
  print(answer is! double);
}
```

`42` is an `int`, and every `int` is also a `num`.

### runtimeType

**`runtimeType`** = the exact type of a value, right now.

- Use it to **look** at a type while learning or fixing a bug.
- Use `is` in real code, to **decide** something.

**Simple lesson:** Dart checks types before running, and `is` lets you check them while running.

## Converting Text to Numbers

Text from a user, a file or the internet is a `String`.
To do maths with it, you must **convert** it.

**Explicit conversion** = you ask Dart to turn one type into another.

### int.parse()

**`int.parse(text)`** = turns text like `'85'` into the `int` `85`.

Press **Next step** to watch the text become a number.

Now with real input. Type two marks in the **Input** box, one per line:

```dart runnable stdin="85\n90" title="Adding two marks typed by the user"
import 'dart:io';

void main() {
  print('Maths marks:');
  int maths = int.parse(stdin.readLineSync()!);
  print('Science marks:');
  int science = int.parse(stdin.readLineSync()!);
  print('Total: ${maths + science}');
}
```

The `!` after `readLineSync()` says "I am sure there is a line here". You will learn it in **Null Safety**.

### double.parse() and num.parse()

- **`double.parse(text)`** = turns text into a `double`.
- **`num.parse(text)`** = gives an `int` for `'12'` and a `double` for `'2.5'`.

```dart runnable title="Parsing decimals"
void main() {
  var height = double.parse('1.48');
  var bonus = num.parse('2.5');
  var count = num.parse('12');
  print(height + 0.02);
  print(bonus + 1);
  print(count.runtimeType);
}
```

### When Parsing Fails

`int.parse()` needs digits only. Run this:

```dart runnable expect-error title="parse() cannot read words"
void main() {
  var marks = int.parse('ninety');
  print(marks);
}
```

The program **crashes** with a `FormatException`. The text could not be read as a number.

**Simple lesson:** `parse()` turns text into a number, but it crashes on text that is not a number.

## Safe Parsing with tryParse()

**`tryParse(text)`** = like `parse()`, but gives `null` instead of crashing.

Add `?? 0` to use a default when the text was not a number:

```dart runnable stdin="seventy" title="A safe way to read marks"
import 'dart:io';

void main() {
  print('Enter marks:');
  var text = stdin.readLineSync() ?? '';
  var marks = int.tryParse(text);
  print('tryParse gave: $marks');
  var safeMarks = int.tryParse(text) ?? 0;
  print('Using: $safeMarks');
}
```

Change the input to `70` and press **Run** again.

- `int.tryParse(text)` gives a number, or `null`.
- `?? 0` means "if it is null, use 0 instead" (see **Null Safety**).
- `double.tryParse()` works the same way for decimals.

**Simple lesson:** use `tryParse()` for anything a person types, so a typo never crashes your app.

## Converting Numbers to Text

### toString()

**`toString()`** = turns any value into a `String`.

```dart runnable title="Numbers become text"
void main() {
  int marks = 92;
  String text = marks.toString();
  print(text + ' out of 100');

  double average = 87.456;
  print(average.toStringAsFixed(1));
  print(average.toStringAsFixed(2));
}
```

- `toString()` lets you join a number with other text using `+`.
- **`toStringAsFixed(n)`** = text with exactly `n` digits after the decimal point.

### Between int and double

- **`toInt()`** = cuts off the decimal part: `9.99.toInt()` gives `9`.
- **`round()`** = rounds to the nearest whole number: `9.5.round()` gives `10`.
- **`toDouble()`** = turns an `int` into a `double`: `9.toDouble()` gives `9.0`.

```dart runnable title="From double to int"
void main() {
  double price = 99.75;
  print(price.toInt());
  print(price.round());
  print(price.floor());
  print(price.ceil());
}
```

**Simple lesson:** `toString()` turns values into text, and `toInt()` or `round()` turn decimals into whole numbers.

## Type Casting

**Type casting** = telling Dart "treat this value as this type", with `as`.

```dart
dynamic value = 'Green Valley';
String school = value as String;
```

If you are wrong, the program crashes:

```dart
dynamic value = 'hello';
int number = value as int;
```

Real Dart stops with an error like `type 'String' is not a subtype of type 'int' in type cast`.

In this course's runner, `as` is not checked yet, so a wrong cast does not crash here.

Real Dart does check it. Never rely on a wrong cast.

### Safe Casting Practices

Check with `is` first. Then Dart already knows the type, and you do not need `as` at all.

```dart runnable title="Check first, then use"
void main() {
  dynamic value = 'green valley';
  if (value is String) {
    print(value.toUpperCase());
  }
  value = 42;
  if (value is int) {
    print(value + 8);
  }
}
```

**Type promotion** = after `if (value is String)`, Dart treats `value` as a `String` inside that block.

**Easy way to remember**

- Text to number: `int.parse()` if you are sure, `int.tryParse()` if a person typed it.
- Number to text: `toString()`.
- Unsure of a type: check with `is` before you use it.

**Simple lesson:** prefer `is` checks over `as` casts, because a check cannot crash.

## TL;DR

1. A **type** says what kind of value a variable holds: `int`, `double`, `num`, `String`, `bool`.
2. `dynamic` turns off checks, `Object` holds anything safely, and `Null` and `Never` are special.
3. **Type inference:** `var x = 5;` makes `x` an `int` for good.
4. **Check:** `x is int`, `x.runtimeType`. **Cast:** check with `is`, then use, or `as` when sure.
5. **Convert:** `int.parse`, `double.parse`, `tryParse` for safety, `toString()`, `toStringAsFixed()`.

## Common mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| `int age = '13';` | Quotes do not matter | Quotes make text | `A value of type 'String' can't be assigned to a variable of type 'int'`. |
| `int price = 99.5;` | int can hold decimals | Use `double` for decimals | `A value of type 'double' can't be assigned to a variable of type 'int'`. |
| `bool ok = 'true';` | `'true'` is a bool | Write `true` without quotes | A type error. |
| `True` or `TRUE` | Case does not matter | Write `true` in small letters | `Undefined name 'True'`. |
| A phone number as `int` | All digits are numbers | Use `String` when you never do maths on it | Leading zeros are lost, and long numbers look odd. |
| `dynamic` everywhere | dynamic is easier | Use real types | Mistakes appear only while the program runs. |
| `String name = null;` | Any variable can be empty | Use `String?` if it may be null | `The value 'null' can't be assigned`. |
| Adding text numbers | `'85' + '90'` is 175 | Parse first: `int.parse('85')` | You get `'8590'`. |
| `int.parse` on user input | People always type digits | Use `int.tryParse` with `??` | A `FormatException` crash. |
| `var x = 5;` then `x = 'five';` | var allows any type | var keeps the first type | A type error. |
| Joining a number to text with `+` | `'Total: ' + 92` works | Use `$` or `toString()` | A type error. |
| `int.parse('9.5')` | parse handles decimals | Use `double.parse` | A `FormatException`. |
| Casting without checking | `as` is always safe | Check with `is` first | A crash in real Dart. |
| `toInt()` to round | `9.99.toInt()` is 10 | `toInt()` cuts, `round()` rounds | You get 9. |

## Check Yourself

## Exercises

## What to Remember

- Every value has a type, and Dart checks it before the program runs.
- Pick `int` for whole numbers, `double` for decimals, `String` for text and `bool` for yes/no.
- `var` lets Dart infer the type, and the type stays fixed.
- Use `tryParse` when text might not be a number.
- Check with `is` before you cast.

Next: **Operators**. You will learn how to do maths, compare values and combine conditions.
