Skip to content

Dart for JS/TS Developers

Dart is a strongly typed, sound null-safe language that compiles to native ARM and JavaScript. If you know TypeScript you already understand most of it — the type syntax is different but the concepts are the same. This lesson maps the key Dart features onto their TypeScript equivalents so you can start reading Flutter code immediately.

TypeScript’s string | null union becomes Dart’s String?. The ? suffix on any type means “this value may be null.” Without ?, the type is guaranteed non-null and the compiler enforces it at every assignment.

React
// TypeScript
let name: string = 'Ava';
let maybeAge: number | null = null;
let definiteAge: number = 30;
function greet(n: string): string {
return `Hello, ${n}!`;
}
Flutter
// Dart
String name = 'Ava';
int? maybeAge = null;
int definiteAge = 30;
String greet(String n) {
return 'Hello, $n!';
}
React
// TypeScript
let counter = 0; // mutable
const MAX = 100; // runtime constant
const PI = 3.14159; // runtime constant
// 'as const' for compile-time literal
const COLORS = ['red', 'green'] as const;
Flutter
// Dart
var counter = 0; // mutable, type inferred
final max = 100; // runtime constant (set once)
const pi = 3.14159; // compile-time constant
// const list = compile-time literal
const colors = ['red', 'green'];
React
// TypeScript
class User {
readonly id: string;
name: string;
constructor(id: string, name: string) {
this.id = id;
this.name = name;
}
greet(): string {
return `Hi, I'm ${this.name}`;
}
}
const u = new User('1', 'Ava');
console.log(u.greet());
Flutter
// Dart
class User {
final String id;
String name;
User(this.id, this.name); // shorthand constructor
String greet() => 'Hi, I\'m $name';
}
final u = User('1', 'Ava');
print(u.greet());
React
// TypeScript
async function fetchUser(id: string): Promise<User> {
const res = await fetch(`/api/users/${id}`);
return res.json() as Promise<User>;
}
// Usage
const user = await fetchUser('42');
Flutter
// Dart
Future<User> fetchUser(String id) async {
final res = await http.get(Uri.parse('/api/users/$id'));
return User.fromJson(jsonDecode(res.body));
}
// Usage
final user = await fetchUser('42');

Future<T> is Dart’s Promise<T>. The async/await syntax is identical. Dart also has Stream<T> for sequences of async values — the equivalent of an async generator / RxJS Observable.

React
// TypeScript
const nums: number[] = [1, 2, 3];
const map: Record<string, number> = { a: 1, b: 2 };
const set: Set<string> = new Set(['x', 'y']);
// spread
const more = [...nums, 4, 5];
// conditional item
const isAdmin = true;
const items = ['home', ...(isAdmin ? ['admin'] : [])];
Flutter
// Dart
List<int> nums = [1, 2, 3];
Map<String, int> map = {'a': 1, 'b': 2};
Set<String> set = {'x', 'y'};
// spread
final more = [...nums, 4, 5];
// collection-if (Dart-native syntax)
final isAdmin = true;
final items = [
'home',
if (isAdmin) 'admin',
];
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

// Pure Dart logic — same as you would write in Node/TS
List<String> buildGreetings(List<String> names, {bool formal = false}) {
  return [
    for (final name in names)
      formal ? 'Good day, $name.' : 'Hey, $name!',
  ];
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    const names = ['Ava', 'Ben', 'Cleo'];
    final greetings = buildGreetings(names, formal: false);

    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(title: const Text('Dart for JS Devs')),
        body: ListView(
          padding: const EdgeInsets.all(16),
          children: [
            for (final g in greetings)
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(12),
                  child: Text(g, style: const TextStyle(fontSize: 16)),
                ),
              ),
          ],
        ),
      ),
    );
  }
}
What is the Dart equivalent of TypeScript's `string | null`?
What is the difference between `final` and `const` in Dart?
What is Dart's equivalent of a TypeScript `Promise<T>`?
Which Dart feature lets you conditionally include an item in a list literal without `.filter()`?