CINXE.COM

The Dart type system | Dart

<!doctype html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="x-ua-compatible" content="ie=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><script>!function(e,t,a,n){e[n]=e[n]||[],e[n].push({"gtm.start":(new Date).getTime(),event:"gtm.js"});var g=t.getElementsByTagName(a)[0],m=t.createElement(a);m.async=!0,m.src="https://www.googletagmanager.com/gtm.js?id=GTM-5VSZM5J",g.parentNode.insertBefore(m,g)}(window,document,"script","dataLayer")</script><meta name="description" content="Why and how to write sound Dart code."><title>The Dart type system | Dart</title><link rel="icon" sizes="64x64" href="/assets/img/logo/dart-64.png" eleventy:ignore><link href="/assets/img/touch-icon-iphone.png" rel="apple-touch-icon" eleventy:ignore><link href="/assets/img/touch-icon-ipad.png" rel="apple-touch-icon" sizes="152x152" eleventy:ignore><link href="/assets/img/touch-icon-iphone-retina.png" rel="apple-touch-icon" sizes="180x180" eleventy:ignore><link href="/assets/img/touch-icon-ipad-retina.png" rel="apple-touch-icon" sizes="167x167" eleventy:ignore><meta name="twitter:card" content="summary"><meta name="twitter:site" content="@dart_lang"><meta name="twitter:title" content="The Dart type system"><meta name="twitter:description" content="Why and how to write sound Dart code."><meta property="og:title" content="The Dart type system"><meta property="og:description" content="Why and how to write sound Dart code."><meta property="og:url" content="/language/type-system/"><meta property="og:image" content="/assets/img/logo/dart-logo-for-shares.png?2" eleventy:ignore><link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Google+Sans:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Google+Sans+Display:wght@400&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Google+Sans+Mono:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Google+Sans+Text:wght@400;500;700&display=swap" rel="stylesheet"><link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0..1,0" rel="stylesheet"><link rel="stylesheet" href="/assets/css/main.css?v=3"><script src="/assets/js/os-tabs.js?v=3"></script><script src="/assets/js/main.js?v=3"></script><script>!function(e,a,t,n,c,o,s){e.GoogleAnalyticsObject=c,e[c]=e[c]||function(){(e[c].q=e[c].q||[]).push(arguments)},e[c].l=1*new Date,o=a.createElement(t),s=a.getElementsByTagName(t)[0],o.async=1,o.src="//www.google-analytics.com/analytics.js",s.parentNode.insertBefore(o,s)}(window,document,"script",0,"ga"),ga("create","UA-26406144-4","auto"),ga("send","pageview")</script></head><body class="default.html"><a id="skip-to-main" class="filled-button" href="#site-content-title" tabindex="1">Skip to main content</a><section id="cookie-notice"><div class="container"><p>dart.dev uses cookies from Google to deliver and enhance the quality of its services and to analyze traffic.</p><div class="button-group"><a class="text-button" href="https://policies.google.com/technologies/cookies" target="_blank" rel="noopener">Learn more</a> <button id="cookie-consent" class="filled-button">OK, got it</button></div></div></section><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-5VSZM5J" height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript><div id="site-banner" role="alert"><p>Announcing Dart 3.7! Find out about updates to the language, analyzer, pub.dev, and more, in the <a href="https://medium.com/dartlang/announcing-dart-3-7-bf864a1b195c" target="_blank">blog post</a>.</p></div><header id="site-header"><nav id="mainnav"><div id="menu-toggle"><span class="material-symbols" title="Toggle side navigation menu." aria-label="Toggle side navigation menu." type="button">menu</span></div><a href="/" class="brand" title="Dart"><img src="/assets/img/logo/logo-white-text.svg" alt="Dart"></a><ul class="navbar"><li><a href="/overview" class="nav-link">Overview</a></li><li class="mainnav__get-started"><a href="/docs" class="nav-link active"><span>Docs</span></a></li><li><a href="/community" class="nav-link">Community</a></li><li><a href="/#try-dart" class="nav-link">Try Dart</a></li><li><a href="/get-dart" class="nav-link">Get Dart</a></li><li class="searchfield"><form action="/search" class="site-header-search form-inline" id="cse-search-box"><input type="hidden" name="cx" value="011220921317074318178:_yy-tmb5t_i"> <input type="hidden" name="ie" value="UTF-8"> <input type="hidden" name="hl" value="en"> <input class="site-header-searchfield form-control search-field" type="search" name="q" id="search-main" autocomplete="off" placeholder="Search" aria-label="Search"></form></li></ul></nav></header><div id="site-below-header"><div id="site-main-row"><div id="sidenav"><form action="/search/" class="site-header-search form-inline"><input class="site-header-searchfield form-control search-field" type="search" name="q" id="search-side" autocomplete="off" placeholder="Search" aria-label="Search"></form><ul class="navbar-nav"><li aria-hidden="true"><div class="sidenav-divider"></div></li><li class="nav-item"><a href="/overview" class="nav-link">Overview</a></li><li class="nav-item"><a href="/community" class="nav-link">Community</a></li><li class="nav-item"><a href="https://dartpad.dev" class="nav-link">Try Dart</a></li><li class="nav-item"><a href="/get-dart" class="nav-link">Get Dart</a></li><li class="nav-item"><a href="/docs" class="nav-link">Docs</a></li><li aria-hidden="true"><div class="sidenav-divider"></div></li></ul><ul class="nav"><li class="nav-item"><button class="nav-link active collapsible" data-toggle="collapse" data-target="#-sidenav-1" role="button" aria-expanded="true" aria-controls="-sidenav-1"><span>Language</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-1"><li class="nav-item"><a class="nav-link" href="/language"><div><span>Introduction</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-2" role="button" aria-expanded="false" aria-controls="-sidenav-1-2"><span>Syntax basics</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-2"><li class="nav-item"><a class="nav-link" href="/language/variables"><div><span>Variables</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/operators"><div><span>Operators</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/comments"><div><span>Comments</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/metadata"><div><span>Metadata</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/libraries"><div><span>Libraries & imports</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/keywords"><div><span>Keywords</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link active collapsible" data-toggle="collapse" data-target="#-sidenav-1-3" role="button" aria-expanded="true" aria-controls="-sidenav-1-3"><span>Types</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-1-3"><li class="nav-item"><a class="nav-link" href="/language/built-in-types"><div><span>Built-in types</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/records"><div><span>Records</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/collections"><div><span>Collections</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/generics"><div><span>Generics</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/typedefs"><div><span>Typedefs</span></div></a></li><li class="nav-item"><a class="nav-link active" href="/language/type-system"><div><span>Type system</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-4" role="button" aria-expanded="false" aria-controls="-sidenav-1-4"><span>Patterns</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-4"><li class="nav-item"><a class="nav-link" href="/language/patterns"><div><span>Overview & usage</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/pattern-types"><div><span>Pattern types</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://codelabs.developers.google.com/codelabs/dart-patterns-records" target="_blank" rel="noopener"><div><span>Applied tutorial</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/language/functions"><div><span>Functions</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-6" role="button" aria-expanded="false" aria-controls="-sidenav-1-6"><span>Control flow</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-6"><li class="nav-item"><a class="nav-link" href="/language/loops"><div><span>Loops</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/branches"><div><span>Branches</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/error-handling"><div><span>Error handling</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-7" role="button" aria-expanded="false" aria-controls="-sidenav-1-7"><span>Classes & objects</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-7"><li class="nav-item"><a class="nav-link" href="/language/classes"><div><span>Classes</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/constructors"><div><span>Constructors</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/methods"><div><span>Methods</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/extend"><div><span>Extend a class</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/mixins"><div><span>Mixins</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/enums"><div><span>Enums</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/extension-methods"><div><span>Extension methods</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/extension-types"><div><span>Extension types</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/callable-objects"><div><span>Callable objects</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-8" role="button" aria-expanded="false" aria-controls="-sidenav-1-8"><span>Class modifiers</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-8"><li class="nav-item"><a class="nav-link" href="/language/class-modifiers"><div><span>Overview & usage</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/class-modifiers-for-apis"><div><span>Class modifiers for API maintainers</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/modifier-reference"><div><span>Reference</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-9" role="button" aria-expanded="false" aria-controls="-sidenav-1-9"><span>Concurrency</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-9"><li class="nav-item"><a class="nav-link" href="/language/concurrency"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/async"><div><span>Asynchronous support</span></div></a></li><li class="nav-item"><a class="nav-link" href="/language/isolates"><div><span>Isolates</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-1-10" role="button" aria-expanded="false" aria-controls="-sidenav-1-10"><span>Null safety</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-1-10"><li class="nav-item"><a class="nav-link" href="/null-safety"><div><span>Sound null safety</span></div></a></li><li class="nav-item"><a class="nav-link" href="/null-safety/migration-guide"><div><span>Migrating to null safety</span></div></a></li><li class="nav-item"><a class="nav-link" href="/null-safety/understanding-null-safety"><div><span>Understanding null safety</span></div></a></li><li class="nav-item"><a class="nav-link" href="/null-safety/unsound-null-safety"><div><span>Unsound null safety</span></div></a></li><li class="nav-item"><a class="nav-link" href="/null-safety/faq"><div><span>FAQ</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-2" role="button" aria-expanded="false" aria-controls="-sidenav-2"><span>Core libraries</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-2"><li class="nav-item"><a class="nav-link" href="/libraries"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-core"><div><span>dart:core</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-async"><div><span>dart:async</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-math"><div><span>dart:math</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-convert"><div><span>dart:convert</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/dart-io"><div><span>dart:io</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop"><div><span>dart:js_interop</span></div></a></li><div class="sidenav-divider"></div><li class="nav-item"><a class="nav-link" href="/libraries/collections/iterables"><div><span>Iterable collections</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-2-10" role="button" aria-expanded="false" aria-controls="-sidenav-2-10"><span>Asynchronous programming</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-2-10"><li class="nav-item"><a class="nav-link" href="/libraries/async/async-await"><div><span>Tutorial</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/async/futures-error-handling"><div><span>Futures and error handling</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/async/using-streams"><div><span>Using streams</span></div></a></li><li class="nav-item"><a class="nav-link" href="/libraries/async/creating-streams"><div><span>Creating streams</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-3" role="button" aria-expanded="false" aria-controls="-sidenav-3"><span>Effective Dart</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-3"><li class="nav-item"><a class="nav-link" href="/effective-dart"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/style"><div><span>Style</span></div></a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/documentation"><div><span>Documentation</span></div></a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/usage"><div><span>Usage</span></div></a></li><li class="nav-item"><a class="nav-link" href="/effective-dart/design"><div><span>Design</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-4" role="button" aria-expanded="false" aria-controls="-sidenav-4"><span>Packages</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-4"><li class="nav-item"><a class="nav-link" href="/tools/pub/packages"><div><span>How to use packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/useful-packages"><div><span>Commonly used packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/create-packages"><div><span>Creating packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/publishing"><div><span>Publishing packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/writing-package-pages"><div><span>Writing package pages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/workspaces"><div><span>Workspaces (monorepo support)</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-4-7" role="button" aria-expanded="false" aria-controls="-sidenav-4-7"><span>Package reference</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-4-7"><li class="nav-item"><a class="nav-link" href="/tools/pub/dependencies"><div><span>Dependencies</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/glossary"><div><span>Glossary</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/package-layout"><div><span>Package layout conventions</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/environment-variables"><div><span>Pub environment variables</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/pubspec"><div><span>Pubspec file</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/troubleshoot"><div><span>Troubleshooting pub</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/verified-publishers"><div><span>Verified publishers</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/security-advisories"><div><span>Security advisories</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/versioning"><div><span>Versioning</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/custom-package-repositories"><div><span>Custom package repositories</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/tools/pub/private-files"><div><span>What not to commit</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-5" role="button" aria-expanded="false" aria-controls="-sidenav-5"><span>Development</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-5"><li class="nav-item"><a class="nav-link" href="/libraries/serialization/json"><div><span>JSON serialization</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/language/number-representation"><div><span>Number representation</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/google-apis"><div><span>Google APIs</span></div></a></li><li class="nav-item"><a class="nav-link" href="/multiplatform-apps"><div><span>Multi-platform apps</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-5-5" role="button" aria-expanded="false" aria-controls="-sidenav-5-5"><span>Command-line & server apps</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-5-5"><li class="nav-item"><a class="nav-link" href="/server"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/get-started"><div><span>Get started</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/cmdline"><div><span>Write command-line apps</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/fetch-data"><div><span>Fetch data from the internet</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials/server/httpserver"><div><span>Write HTTP servers</span></div></a></li><li class="nav-item"><a class="nav-link" href="/server/libraries"><div><span>Libraries & packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/server/google-cloud"><div><span>Google Cloud</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-5-6" role="button" aria-expanded="false" aria-controls="-sidenav-5-6"><span>Web apps</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-5-6"><li class="nav-item"><a class="nav-link" href="/web"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/get-started"><div><span>Get started</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/deployment"><div><span>Deployment</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/libraries"><div><span>Libraries & packages</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/wasm"><div><span>Wasm compilation</span></div></a></li></ul></li><li class="nav-item"><a class="nav-link" href="/libraries/core/environment-declarations"><div><span>Environment declarations</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-6" role="button" aria-expanded="false" aria-controls="-sidenav-6"><span>Interoperability</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-6"><li class="nav-item"><a class="nav-link" href="/interop/c-interop"><div><span>C interop</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/objective-c-interop"><div><span>Objective-C & Swift interop</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/java-interop"><div><span>Java & Kotlin interop</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-6-4" role="button" aria-expanded="false" aria-controls="-sidenav-6-4"><span>JavaScript interop</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-6-4"><li class="nav-item"><a class="nav-link" href="/interop/js-interop"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/usage"><div><span>Usage</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/js-types"><div><span>JS types</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/tutorials"><div><span>Tutorials</span></div></a></li><li class="nav-item"><a class="nav-link" href="/interop/js-interop/past-js-interop"><div><span>Past JS interop</span></div></a></li><div class="sidenav-divider"></div><li class="nav-item"><a class="nav-link" href="/interop/js-interop/package-web"><div><span>Web interop</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-7" role="button" aria-expanded="false" aria-controls="-sidenav-7"><span>Tools & techniques</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7"><li class="nav-item"><a class="nav-link" href="/tools"><div><span>Overview</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-2" role="button" aria-expanded="false" aria-controls="-sidenav-7-2"><span>Editors & debuggers</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-2"><li class="nav-item"><a class="nav-link" href="/tools/jetbrains-plugin"><div><span>IntelliJ & Android Studio</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/vs-code"><div><span>VS Code</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-devtools"><div><span>Dart DevTools</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-2-4" role="button" aria-expanded="false" aria-controls="-sidenav-7-2-4"><span>DartPad</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-2-4"><li class="nav-item"><a class="nav-link" href="/tools/dartpad"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dartpad/troubleshoot"><div><span>Troubleshooting DartPad</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-3" role="button" aria-expanded="false" aria-controls="-sidenav-7-3"><span>Command-line tools</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-3"><li class="nav-item"><button class="nav-link collapsible" data-toggle="collapse" data-target="#-sidenav-7-3-1" role="button" aria-expanded="true" aria-controls="-sidenav-7-3-1"><span>Dart SDK</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-7-3-1"><li class="nav-item"><a class="nav-link" href="/tools/sdk"><div><span>Overview</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-tool"><div><span>dart</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-analyze"><div><span>dart analyze</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-compile"><div><span>dart compile</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-create"><div><span>dart create</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-doc"><div><span>dart doc</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-fix"><div><span>dart fix</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-format"><div><span>dart format</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-info"><div><span>dart info</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/pub/cmd"><div><span>dart pub</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-run"><div><span>dart run</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dart-test"><div><span>dart test</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/dartaotruntime"><div><span>dartaotruntime</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/experiment-flags"><div><span>Experiment flags</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible" data-toggle="collapse" data-target="#-sidenav-7-3-2" role="button" aria-expanded="true" aria-controls="-sidenav-7-3-2"><span>Other command-line tools</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-7-3-2"><li class="nav-item"><a class="nav-link" href="/tools/build_runner"><div><span>build_runner</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/webdev"><div><span>webdev</span></div></a></li></ul></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-4" role="button" aria-expanded="false" aria-controls="-sidenav-7-4"><span>Static analysis</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-4"><li class="nav-item"><a class="nav-link" href="/tools/analysis"><div><span>Customizing static analysis</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/non-promotion-reasons"><div><span>Fixing type promotion failures</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/linter-rules"><div><span>Linter rules</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tools/diagnostic-messages"><div><span>Diagnostic messages</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-7-5" role="button" aria-expanded="false" aria-controls="-sidenav-7-5"><span>Testing & optimization</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-7-5"><li class="nav-item"><a class="nav-link" href="/tools/testing"><div><span>Testing</span></div></a></li><li class="nav-item"><a class="nav-link" href="/web/debugging"><div><span>Debugging web apps</span></div></a></li></ul></li></ul></li><li aria-hidden="true"><div class="sidenav-divider"></div></li><li class="nav-item"><button class="nav-link collapsed collapsible" data-toggle="collapse" data-target="#-sidenav-9" role="button" aria-expanded="false" aria-controls="-sidenav-9"><span>Resources</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-9"><li class="nav-item"><a class="nav-link" href="/resources/dart-cheatsheet"><div><span>Language cheatsheet</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/breaking-changes"><div><span>Breaking changes</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/language/evolution"><div><span>Language evolution</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/language/spec"><div><span>Language specification</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/dart-3-migration"><div><span>Dart 3 migration guide</span></div></a></li><li class="nav-item"><button class="nav-link collapsible collapsed" data-toggle="collapse" data-target="#-sidenav-9-6" role="button" aria-expanded="false" aria-controls="-sidenav-9-6"><span>Coming from ...</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse" id="-sidenav-9-6"><li class="nav-item"><a class="nav-link" href="/resources/coming-from/js-to-dart"><div><span>JavaScript to Dart</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/coming-from/swift-to-dart"><div><span>Swift to Dart</span></div></a></li></ul></li><div class="sidenav-divider"></div><li class="nav-item"><a class="nav-link" href="/resources/faq"><div><span>FAQ</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/glossary"><div><span>Glossary</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/books"><div><span>Books</span></div></a></li><li class="nav-item"><a class="nav-link" href="/resources/videos"><div><span>Videos</span></div></a></li><li class="nav-item"><a class="nav-link" href="/tutorials"><div><span>Tutorials</span></div></a></li></ul></li><li class="nav-item"><button class="nav-link collapsible" data-toggle="collapse" data-target="#-sidenav-10" role="button" aria-expanded="true" aria-controls="-sidenav-10"><span>Related sites</span> <span class="material-symbols expander" aria-hidden="true">expand_more</span></button><ul class="nav collapse show" id="-sidenav-10"><li class="nav-item"><a class="nav-link" href="https://api.dart.dev" target="_blank" rel="noopener"><div><span>API reference</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://medium.com/dartlang" target="_blank" rel="noopener"><div><span>Blog</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://dartpad.dev" target="_blank" rel="noopener"><div><span>DartPad (online editor)</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://flutter.dev" target="_blank" rel="noopener"><div><span>Flutter</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li><li class="nav-item"><a class="nav-link" href="https://pub.dev" target="_blank" rel="noopener"><div><span>Package site</span><span class="material-symbols" aria-hidden="true">open_in_new</span></div></a></li></ul></li></ul></div><main id="page-content"><div id="site-toc--side" class="site-toc"><header class="site-toc__title">Contents</header><ul class="section-nav"><li class="toc-entry nav-item"><a class="nav-link" href="#what-is-soundness">What is soundness?</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#the-benefits-of-soundness">The benefits of soundness</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#tips-for-passing-static-analysis">Tips for passing static analysis</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#use-sound-return-types-when-overriding-methods">Use sound return types when overriding methods</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#use-sound-parameter-types-when-overriding-methods">Use sound parameter types when overriding methods</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#dont-use-a-dynamic-list-as-a-typed-list">Don't use a dynamic list as a typed list</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#runtime-checks">Runtime checks</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#implicit-downcasts-from-dynamic">Implicit downcasts from dynamic</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#type-inference">Type inference</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#field-and-method-inference">Field and method inference</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#static-field-inference">Static field inference</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#local-variable-inference">Local variable inference</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#type-argument-inference">Type argument inference</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#substituting-types">Substituting types</a><ul class="nav"><li class="toc-entry nav-item"><a class="nav-link" href="#simple-type-assignment">Simple type assignment</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#generic-type-assignment">Generic type assignment</a></li><li class="toc-entry nav-item"><a class="nav-link" href="#methods">Methods</a></li></ul></li><li class="toc-entry nav-item"><a class="nav-link" href="#other-resources">Other resources</a></li></ul></div><article><div class="content"><div id="site-content-title"><h1>The Dart type system</h1></div><div id="site-toc--inline" class="site-toc toc-collapsible toc-collapsed"><header class="site-toc__title">Contents <span class="site-toc--inline__toggle toc-toggle-down"><i class="material-symbols">keyboard_arrow_down</i></span> <span class="site-toc--inline__toggle toc-toggle-up"><i class="material-symbols">keyboard_arrow_up</i></span></header><ul class="section-nav"><li class="toc-entry"><a href="#what-is-soundness">What is soundness?</a></li><li class="toc-entry"><a href="#the-benefits-of-soundness">The benefits of soundness</a></li><li class="toc-entry"><a href="#tips-for-passing-static-analysis">Tips for passing static analysis</a><ul><li class="toc-entry"><a href="#use-sound-return-types-when-overriding-methods">Use sound return types when overriding methods</a></li><li class="toc-entry"><a href="#use-sound-parameter-types-when-overriding-methods">Use sound parameter types when overriding methods</a></li><li class="toc-entry"><a href="#dont-use-a-dynamic-list-as-a-typed-list">Don't use a dynamic list as a typed list</a></li></ul></li><li class="toc-entry"><a href="#runtime-checks">Runtime checks</a><ul><li class="toc-entry"><a href="#implicit-downcasts-from-dynamic">Implicit downcasts from dynamic</a></li></ul></li><li class="toc-entry"><a href="#type-inference">Type inference</a><ul><li class="toc-entry"><a href="#field-and-method-inference">Field and method inference</a></li><li class="toc-entry"><a href="#static-field-inference">Static field inference</a></li><li class="toc-entry"><a href="#local-variable-inference">Local variable inference</a></li><li class="toc-entry"><a href="#type-argument-inference">Type argument inference</a></li></ul></li><li class="toc-entry"><a href="#substituting-types">Substituting types</a><ul><li class="toc-entry"><a href="#simple-type-assignment">Simple type assignment</a></li><li class="toc-entry"><a href="#generic-type-assignment">Generic type assignment</a></li><li class="toc-entry"><a href="#methods">Methods</a></li></ul></li><li class="toc-entry"><a href="#other-resources">Other resources</a></li></ul><span class="site-toc--inline__toggle toc-toggle-more-items"><i class="material-symbols">more_horiz</i></span></div> <?code-excerpt replace="/ *\/\/\s+ignore_for_file:[^\n]+\n//g; /([A-Z]\w*)\d\b/$1/g; /\b(main)\d\b/$1/g; /(^|\n) *\/\/\s+ignore:[^\n]+\n/$1/g; /(\n[^\n]+) *\/\/\s+ignore:[^\n]+\n/$1\n/g"?> <?code-excerpt path-base="type_system"?> <p>The Dart language is type safe: it uses a combination of static type checking and <a href="#runtime-checks">runtime checks</a> to ensure that a variable's value always matches the variable's static type, sometimes referred to as sound typing. Although <em>types</em> are mandatory, type <em>annotations</em> are optional because of <a href="#type-inference">type inference</a>.</p><p>One benefit of static type checking is the ability to find bugs at compile time using Dart's <a href="/tools/analysis">static analyzer.</a></p><p>You can fix most static analysis errors by adding type annotations to generic classes. The most common generic classes are the collection types <code>List&lt;T&gt;</code> and <code>Map&lt;K,V&gt;</code>.</p><p>For example, in the following code the <code>printInts()</code> function prints an integer list, and <code>main()</code> creates a list and passes it to <code>printInts()</code>.</p> <?code-excerpt "lib/strong_analysis.dart (opening-example)" replace="/list(?=\))/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-fails-sa"><span class="code-block-tag">✗ static analysis: failure</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> printInts</span><span style="color:#222222">(</span><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">int</span><span style="color:#222222">> a) => </span><span style="color:#6200EE">print</span><span style="color:#222222">(a);</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#222222"> list = [];</span></span> <span class="line"><span style="color:#222222"> list.</span><span style="color:#6200EE">add</span><span style="color:#222222">(</span><span style="color:#11796D">1</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222"> list.</span><span style="color:#6200EE">add</span><span style="color:#222222">(</span><span style="color:#11796D">'2'</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#6200EE"> printInts</span><span style="color:#222222">(</span><mark class="highlight"><span style="color:#222222">list</span></mark><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>The preceding code results in a type error on <code>list</code> (highlighted above) at the call of <code>printInts(list)</code>:</p> <?code-excerpt "analyzer-results-stable.txt" retain="/strong_analysis.*List.*argument_type_not_assignable/" replace="/-(.*?):(.*?):(.*?)-/-/g; /. • (lib|test)\/\w+\.dart:\d+:\d+//g"?> <div class="code-block-wrapper language-plaintext"><div class="code-block-body"><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span>error - The argument type 'List&#x3C;dynamic>' can't be assigned to the parameter type 'List&#x3C;int>'. - argument_type_not_assignable</span></span></code></pre></div></div><p>The error highlights an unsound implicit cast from <code>List&lt;dynamic&gt;</code> to <code>List&lt;int&gt;</code>. The <code>list</code> variable has static type <code>List&lt;dynamic&gt;</code>. This is because the initializing declaration <code>var list = []</code> doesn't provide the analyzer with enough information for it to infer a type argument more specific than <code>dynamic</code>. The <code>printInts()</code> function expects a parameter of type <code>List&lt;int&gt;</code>, causing a mismatch of types.</p><p>When adding a type annotation (<code>&lt;int&gt;</code>) on creation of the list (highlighted below) the analyzer complains that a string argument can't be assigned to an <code>int</code> parameter. Removing the quotes in <code>list.add('2')</code> results in code that passes static analysis and runs with no errors or warnings.</p> <?code-excerpt "test/strong_test.dart (opening-example)" replace="/<int.(?=\[)|2/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-passes-sa"><span class="code-block-tag">✔ static analysis: success</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> printInts</span><span style="color:#222222">(</span><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">int</span><span style="color:#222222">> a) => </span><span style="color:#6200EE">print</span><span style="color:#222222">(a);</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#D43324"> final</span><span style="color:#222222"> list = </span><mark class="highlight"><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">int</span><span style="color:#222222">></span></mark><span style="color:#222222">[];</span></span> <span class="line"><span style="color:#222222"> list.</span><span style="color:#6200EE">add</span><span style="color:#222222">(</span><span style="color:#11796D">1</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222"> list.</span><span style="color:#6200EE">add</span><span style="color:#222222">(</span><mark class="highlight"><span style="color:#11796D">2</span></mark><span style="color:#222222">);</span></span> <span class="line"><span style="color:#6200EE"> printInts</span><span style="color:#222222">(list);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p><a href="https://dartpad.dev/?id=25074a51a00c71b4b000f33b688dedd0">Try it in DartPad</a>.</p><div class="header-wrapper"><h2 id="what-is-soundness">What is soundness?</h2><a class="heading-link" href="#what-is-soundness" aria-label="Link to 'What is soundness?' section">#</a></div><p><em>Soundness</em> is about ensuring your program can't get into certain invalid states. A sound <em>type system</em> means you can never get into a state where an expression evaluates to a value that doesn't match the expression's static type. For example, if an expression's static type is <code>String</code>, at runtime you are guaranteed to only get a string when you evaluate it.</p><p>Dart's type system, like the type systems in Java and C#, is sound. It enforces that soundness using a combination of static checking (compile-time errors) and runtime checks. For example, assigning a <code>String</code> to <code>int</code> is a compile-time error. Casting an object to a <code>String</code> using <code>as String</code> fails with a runtime error if the object isn't a <code>String</code>.</p><div class="header-wrapper"><h2 id="the-benefits-of-soundness">The benefits of soundness</h2><a class="heading-link" href="#the-benefits-of-soundness" aria-label="Link to 'The benefits of soundness' section">#</a></div><p>A sound type system has several benefits:</p><ul><li><p>Revealing type-related bugs at compile time.<br>A sound type system forces code to be unambiguous about its types, so type-related bugs that might be tricky to find at runtime are revealed at compile time.</p></li><li><p>More readable code.<br>Code is easier to read because you can rely on a value actually having the specified type. In sound Dart, types can't lie.</p></li><li><p>More maintainable code.<br>With a sound type system, when you change one piece of code, the type system can warn you about the other pieces of code that just broke.</p></li><li><p>Better ahead of time (AOT) compilation.<br>While AOT compilation is possible without types, the generated code is much less efficient.</p></li></ul><div class="header-wrapper"><h2 id="tips-for-passing-static-analysis">Tips for passing static analysis</h2><a class="heading-link" href="#tips-for-passing-static-analysis" aria-label="Link to 'Tips for passing static analysis' section">#</a></div><p>Most of the rules for static types are easy to understand. Here are some of the less obvious rules:</p><ul><li>Use sound return types when overriding methods.</li><li>Use sound parameter types when overriding methods.</li><li>Don't use a dynamic list as a typed list.</li></ul><p>Let's see these rules in detail, with examples that use the following type hierarchy:</p><img src="/assets/img/language/type-hierarchy.png" alt="a hierarchy of animals where the supertype is Animal and the subtypes are Alligator, Cat, and HoneyBadger. Cat has the subtypes of Lion and MaineCoon"><p><a name="use-proper-return-types"></a></p><div class="header-wrapper"><h3 id="use-sound-return-types-when-overriding-methods">Use sound return types when overriding methods</h3><a class="heading-link" href="#use-sound-return-types-when-overriding-methods" aria-label="Link to 'Use sound return types when overriding methods' section">#</a></div><p>The return type of a method in a subclass must be the same type or a subtype of the return type of the method in the superclass. Consider the getter method in the <code>Animal</code> class:</p> <?code-excerpt "lib/animal.dart (Animal)" replace="/Animal get.*/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Animal</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> chase</span><span style="color:#222222">(</span><span style="color:#0468D7">Animal</span><span style="color:#222222"> a) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#0468D7"> </span><mark class="highlight"><span style="color:#0468D7">Animal</span><span style="color:#D43324"> get</span><span style="color:#222222"> parent => ...</span></mark></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>The <code>parent</code> getter method returns an <code>Animal</code>. In the <code>HoneyBadger</code> subclass, you can replace the getter's return type with <code>HoneyBadger</code> (or any other subtype of <code>Animal</code>), but an unrelated type is not allowed.</p> <?code-excerpt "lib/animal.dart (HoneyBadger)" replace="/(\w+)(?= get)/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-passes-sa"><span class="code-block-tag">✔ static analysis: success</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> HoneyBadger</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Animal</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> @override</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> chase</span><span style="color:#222222">(</span><span style="color:#0468D7">Animal</span><span style="color:#222222"> a) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> @override</span></span> <span class="line"><span style="color:#0468D7"> </span><mark class="highlight"><span style="color:#0468D7">HoneyBadger</span></mark><span style="color:#D43324"> get</span><span style="color:#222222"> parent => ...</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><?code-excerpt "lib/animal.dart (HoneyBadger)" replace="/HoneyBadger get/[!Root!] get/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-fails-sa"><span class="code-block-tag">✗ static analysis: failure</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> HoneyBadger</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Animal</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> @override</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> chase</span><span style="color:#222222">(</span><span style="color:#0468D7">Animal</span><span style="color:#222222"> a) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> @override</span></span> <span class="line"><span style="color:#0468D7"> </span><mark class="highlight"><span style="color:#0468D7">Root</span></mark><span style="color:#D43324"> get</span><span style="color:#222222"> parent => ...</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p><a name="use-proper-param-types"></a></p><div class="header-wrapper"><h3 id="use-sound-parameter-types-when-overriding-methods">Use sound parameter types when overriding methods</h3><a class="heading-link" href="#use-sound-parameter-types-when-overriding-methods" aria-label="Link to 'Use sound parameter types when overriding methods' section">#</a></div><p>The parameter of an overridden method must have either the same type or a supertype of the corresponding parameter in the superclass. Don't &quot;tighten&quot; the parameter type by replacing the type with a subtype of the original parameter.</p><aside class="alert alert-info"><div class="alert-header"><span class="material-symbols" aria-hidden="true">info</span> <span>Note</span></div><div class="alert-content"><p>If you have a valid reason to use a subtype, you can use the <a href="/language/type-system#covariant-keyword"><code>covariant</code> keyword</a>.</p></div></aside><p>Consider the <code>chase(Animal)</code> method for the <code>Animal</code> class:</p> <?code-excerpt "lib/animal.dart (Animal)" replace="/void chase.*/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Animal</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> </span><mark class="highlight"><span style="color:#D43324">void</span><span style="color:#6200EE"> chase</span><span style="color:#222222">(</span><span style="color:#0468D7">Animal</span><span style="color:#222222"> a) {</span></mark></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#0468D7"> Animal</span><span style="color:#D43324"> get</span><span style="color:#222222"> parent => ...</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>The <code>chase()</code> method takes an <code>Animal</code>. A <code>HoneyBadger</code> chases anything. It's OK to override the <code>chase()</code> method to take anything (<code>Object</code>).</p> <?code-excerpt "lib/animal.dart (chase-Object)" replace="/Object/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-passes-sa"><span class="code-block-tag">✔ static analysis: success</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> HoneyBadger</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Animal</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> @override</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> chase</span><span style="color:#222222">(</span><mark class="highlight"><span style="color:#0468D7">Object</span></mark><span style="color:#222222"> a) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> @override</span></span> <span class="line"><span style="color:#0468D7"> Animal</span><span style="color:#D43324"> get</span><span style="color:#222222"> parent => ...</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>The following code tightens the parameter on the <code>chase()</code> method from <code>Animal</code> to <code>Mouse</code>, a subclass of <code>Animal</code>.</p> <?code-excerpt "lib/incorrect_animal.dart (chase-mouse)" replace="/Mouse/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-fails-sa"><span class="code-block-tag">✗ static analysis: failure</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> </span><mark class="highlight"><span style="color:#0468D7">Mouse</span></mark><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Animal</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Cat</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Animal</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> @override</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> chase</span><span style="color:#222222">(</span><mark class="highlight"><span style="color:#0468D7">Mouse</span></mark><span style="color:#222222"> a) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>This code is not type safe because it would then be possible to define a cat and send it after an alligator:</p> <?code-excerpt "lib/incorrect_animal.dart (would-not-be-type-safe)" replace="/Alligator/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Animal</span><span style="color:#222222"> a = </span><span style="color:#0468D7">Cat</span><span style="color:#222222">();</span></span> <span class="line"><span style="color:#222222">a.</span><span style="color:#6200EE">chase</span><span style="color:#222222">(</span><mark class="highlight"><span style="color:#0468D7">Alligator</span></mark><span style="color:#222222">()); </span><span style="color:#6E6E70">// Not type safe or feline safe.</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="dont-use-a-dynamic-list-as-a-typed-list">Don't use a dynamic list as a typed list</h3><a class="heading-link" href="#dont-use-a-dynamic-list-as-a-typed-list" aria-label="Link to 'Don't use a dynamic list as a typed list' section">#</a></div><p>A <code>dynamic</code> list is good when you want to have a list with different kinds of things in it. However, you can't use a <code>dynamic</code> list as a typed list.</p><p>This rule also applies to instances of generic types.</p><p>The following code creates a <code>dynamic</code> list of <code>Dog</code>, and assigns it to a list of type <code>Cat</code>, which generates an error during static analysis.</p> <?code-excerpt "lib/incorrect_animal.dart (invalid-dynamic-list)" replace="/(<dynamic\x3E)(.*?)Error/[!$1!]$2Error/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-fails-sa"><span class="code-block-tag">✗ static analysis: failure</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#0468D7"> List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">Cat</span><span style="color:#222222">> foo = </span><mark class="highlight"><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">dynamic</span><span style="color:#222222">></span></mark><span style="color:#222222">[</span><span style="color:#0468D7">Dog</span><span style="color:#222222">()]; </span><span style="color:#6E6E70">// Error</span></span> <span class="line"><span style="color:#0468D7"> List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">dynamic</span><span style="color:#222222">> bar = &#x3C;</span><span style="color:#0468D7">dynamic</span><span style="color:#222222">>[</span><span style="color:#0468D7">Dog</span><span style="color:#222222">(), </span><span style="color:#0468D7">Cat</span><span style="color:#222222">()]; </span><span style="color:#6E6E70">// OK</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h2 id="runtime-checks">Runtime checks</h2><a class="heading-link" href="#runtime-checks" aria-label="Link to 'Runtime checks' section">#</a></div><p>Runtime checks deal with type safety issues that can't be detected at compile time.</p><p>For example, the following code throws an exception at runtime because it's an error to cast a list of dogs to a list of cats:</p> <?code-excerpt "test/strong_test.dart (runtime-checks)" replace="/animals as[^;]*/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-runtime-fail"><span class="code-block-tag">✗ runtime: failure</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#0468D7"> List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">Animal</span><span style="color:#222222">> animals = &#x3C;</span><span style="color:#0468D7">Dog</span><span style="color:#222222">>[</span><span style="color:#0468D7">Dog</span><span style="color:#222222">()];</span></span> <span class="line"><span style="color:#0468D7"> List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">Cat</span><span style="color:#222222">> cats = </span><mark class="highlight"><span style="color:#222222">animals </span><span style="color:#D43324">as</span><span style="color:#0468D7"> List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">Cat</span><span style="color:#222222">></span></mark><span style="color:#222222">;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="implicit-downcasts-from-dynamic">Implicit downcasts from <code>dynamic</code></h3><a class="heading-link" href="#implicit-downcasts-from-dynamic" aria-label="Link to 'Implicit downcasts from dynamic' section">#</a></div><p>Expressions with a static type of <code>dynamic</code> can be implicitly cast to a more specific type. If the actual type doesn't match, the cast throws an error at run time. Consider the following <code>assumeString</code> method:</p> <?code-excerpt "lib/strong_analysis.dart (downcast-check)" replace="/string = object/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-passes-sa"><span class="code-block-tag">✔ static analysis: success</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">int</span><span style="color:#6200EE"> assumeString</span><span style="color:#222222">(</span><span style="color:#0468D7">dynamic</span><span style="color:#222222"> object) {</span></span> <span class="line"><span style="color:#0468D7"> String</span><span style="color:#222222"> </span><mark class="highlight"><span style="color:#222222">string = object</span></mark><span style="color:#222222">; </span><span style="color:#6E6E70">// Check at run time that `object` is a `String`.</span></span> <span class="line"><span style="color:#D43324"> return</span><span style="color:#222222"> string.length;</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>In this example, if <code>object</code> is a <code>String</code>, the cast succeeds. If it's not a subtype of <code>String</code>, such as <code>int</code>, a <code>TypeError</code> is thrown:</p> <?code-excerpt "lib/strong_analysis.dart (fail-downcast-check)" replace="/1/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-runtime-fail"><span class="code-block-tag">✗ runtime: failure</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">final</span><span style="color:#222222"> length = </span><span style="color:#6200EE">assumeString</span><span style="color:#222222">(</span><mark class="highlight"><span style="color:#11796D">1</span></mark><span style="color:#222222">);</span></span></code></pre></div></div><aside class="alert alert-success"><div class="alert-header"><span class="material-symbols" aria-hidden="true">lightbulb</span> <span>Tip</span></div><div class="alert-content"><p>To prevent implicit downcasts from <code>dynamic</code> and avoid this issue, consider enabling the analyzer's <em>strict casts</em> mode.</p><div class="code-block-wrapper language-yaml"><div class="code-block-header">analysis_options.yaml</div><div class="code-block-body"><span class="code-block-language" title="Language yaml">yaml</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">analyzer</span><span style="color:#222222">:</span></span> <span class="line"><span style="color:#0468D7"> language</span><span style="color:#222222">:</span></span> <span class="line highlighted-line"><span style="color:#0468D7"> strict-casts</span><span style="color:#222222">: </span><span style="color:#11796D">true</span></span></code></pre></div></div><p>To learn more about customizing the analyzer's behavior, check out <a href="/tools/analysis">Customizing static analysis</a>.</p></div></aside><div class="header-wrapper"><h2 id="type-inference">Type inference</h2><a class="heading-link" href="#type-inference" aria-label="Link to 'Type inference' section">#</a></div><p>The analyzer can infer types for fields, methods, local variables, and most generic type arguments. When the analyzer doesn't have enough information to infer a specific type, it uses the <code>dynamic</code> type.</p><p>Here's an example of how type inference works with generics. In this example, a variable named <code>arguments</code> holds a map that pairs string keys with values of various types.</p><p>If you explicitly type the variable, you might write this:</p> <?code-excerpt "lib/strong_analysis.dart (type-inference-1-orig)" replace="/Map<String, Object\?\x3E/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><mark class="highlight"><span style="color:#0468D7">Map</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">String</span><span style="color:#222222">, </span><span style="color:#0468D7">Object</span><span style="color:#222222">?></span></mark><span style="color:#222222"> arguments = {</span><span style="color:#11796D">'argA'</span><span style="color:#222222">: </span><span style="color:#11796D">'hello'</span><span style="color:#222222">, </span><span style="color:#11796D">'argB'</span><span style="color:#222222">: </span><span style="color:#11796D">42</span><span style="color:#222222">};</span></span></code></pre></div></div><p>Alternatively, you can use <code>var</code> or <code>final</code> and let Dart infer the type:</p> <?code-excerpt "lib/strong_analysis.dart (type-inference-1)" replace="/var/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><mark class="highlight"><span style="color:#D43324">var</span></mark><span style="color:#222222"> arguments = {</span><span style="color:#11796D">'argA'</span><span style="color:#222222">: </span><span style="color:#11796D">'hello'</span><span style="color:#222222">, </span><span style="color:#11796D">'argB'</span><span style="color:#222222">: </span><span style="color:#11796D">42</span><span style="color:#222222">}; </span><span style="color:#6E6E70">// Map&#x3C;String, Object></span></span></code></pre></div></div><p>The map literal infers its type from its entries, and then the variable infers its type from the map literal's type. In this map, the keys are both strings, but the values have different types (<code>String</code> and <code>int</code>, which have the upper bound <code>Object</code>). So the map literal has the type <code>Map&lt;String, Object&gt;</code>, and so does the <code>arguments</code> variable.</p><div class="header-wrapper"><h3 id="field-and-method-inference">Field and method inference</h3><a class="heading-link" href="#field-and-method-inference" aria-label="Link to 'Field and method inference' section">#</a></div><p>A field or method that has no specified type and that overrides a field or method from the superclass, inherits the type of the superclass method or field.</p><p>A field that does not have a declared or inherited type but that is declared with an initial value, gets an inferred type based on the initial value.</p><div class="header-wrapper"><h3 id="static-field-inference">Static field inference</h3><a class="heading-link" href="#static-field-inference" aria-label="Link to 'Static field inference' section">#</a></div><p>Static fields and variables get their types inferred from their initializer. Note that inference fails if it encounters a cycle (that is, inferring a type for the variable depends on knowing the type of that variable).</p><div class="header-wrapper"><h3 id="local-variable-inference">Local variable inference</h3><a class="heading-link" href="#local-variable-inference" aria-label="Link to 'Local variable inference' section">#</a></div><p>Local variable types are inferred from their initializer, if any. Subsequent assignments are not taken into account. This may mean that too precise a type may be inferred. If so, you can add a type annotation.</p> <?code-excerpt "lib/strong_analysis.dart (local-var-type-inference-error)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-fails-sa"><span class="code-block-tag">✗ static analysis: failure</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> x = </span><span style="color:#11796D">3</span><span style="color:#222222">; </span><span style="color:#6E6E70">// x is inferred as an int.</span></span> <span class="line"><span style="color:#222222">x = </span><span style="color:#11796D">4.0</span><span style="color:#222222">;</span></span></code></pre></div></div><?code-excerpt "lib/strong_analysis.dart (local-var-type-inference-ok)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-passes-sa"><span class="code-block-tag">✔ static analysis: success</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">num</span><span style="color:#222222"> y = </span><span style="color:#11796D">3</span><span style="color:#222222">; </span><span style="color:#6E6E70">// A num can be double or int.</span></span> <span class="line"><span style="color:#222222">y = </span><span style="color:#11796D">4.0</span><span style="color:#222222">;</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="type-argument-inference">Type argument inference</h3><a class="heading-link" href="#type-argument-inference" aria-label="Link to 'Type argument inference' section">#</a></div><p>Type arguments to constructor calls and <a href="/language/generics#using-generic-methods">generic method</a> invocations are inferred based on a combination of downward information from the context of occurrence, and upward information from the arguments to the constructor or generic method. If inference is not doing what you want or expect, you can always explicitly specify the type arguments.</p> <?code-excerpt "lib/strong_analysis.dart (type-arg-inference)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-passes-sa"><span class="code-block-tag">✔ static analysis: success</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#6E6E70">// Inferred as if you wrote &#x3C;int>[].</span></span> <span class="line"><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">int</span><span style="color:#222222">> listOfInt = [];</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Inferred as if you wrote &#x3C;double>[3.0].</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> listOfDouble = [</span><span style="color:#11796D">3.0</span><span style="color:#222222">];</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70">// Inferred as Iterable&#x3C;int>.</span></span> <span class="line"><span style="color:#D43324">var</span><span style="color:#222222"> ints = listOfDouble.</span><span style="color:#6200EE">map</span><span style="color:#222222">((x) => x.</span><span style="color:#6200EE">toInt</span><span style="color:#222222">());</span></span></code></pre></div></div><p>In the last example, <code>x</code> is inferred as <code>double</code> using downward information. The return type of the closure is inferred as <code>int</code> using upward information. Dart uses this return type as upward information when inferring the <code>map()</code> method's type argument: <code>&lt;int&gt;</code>.</p><div class="header-wrapper"><h4 id="inference-using-bounds">Inference using bounds</h4><a class="heading-link" href="#inference-using-bounds" aria-label="Link to 'Inference using bounds' section">#</a></div><aside class="alert alert-info"><div class="alert-header"><span class="material-symbols" aria-hidden="true">merge_type</span> <span>Version note</span></div><div class="alert-content"><p>Inference using bounds requires a <a href="/resources/language/evolution#language-versioning">language version</a> of at least 3.7.0.</p></div></aside><p>With the inference using bounds feature, Dart's type inference algorithm generates constraints by combining existing constraints with the declared type bounds, not just best-effort approximations.</p><p>This is especially important for <a href="/language/generics/#f-bounds">F-bounded</a> types, where inference using bounds correctly infers that, in the example below, <code>X</code> can be bound to <code>B</code>. Without the feature, the type argument must be specified explicitly: <code>f&lt;B&gt;(C())</code>:</p> <?code-excerpt "lib/strong_analysis.dart (inference-using-bounds)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> A</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">X</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> A</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">X</span><span style="color:#222222">>> {}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> B</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> A</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">B</span><span style="color:#222222">> {}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> C</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> B</span><span style="color:#222222"> {}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> f</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">X</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> A</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">X</span><span style="color:#222222">>>(</span><span style="color:#0468D7">X</span><span style="color:#222222"> x) {}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6200EE"> f</span><span style="color:#222222">(</span><span style="color:#0468D7">B</span><span style="color:#222222">()); </span><span style="color:#6E6E70">// OK.</span></span> <span class="line"></span> <span class="line"><span style="color:#6E6E70"> // OK. Without using bounds, inference relying on best-effort approximations</span></span> <span class="line"><span style="color:#6E6E70"> // would fail after detecting that `C` is not a subtype of `A&#x3C;C>`.</span></span> <span class="line"><span style="color:#6200EE"> f</span><span style="color:#222222">(</span><span style="color:#0468D7">C</span><span style="color:#222222">());</span></span> <span class="line"></span> <span class="line"><span style="color:#6200EE"> f</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">B</span><span style="color:#222222">>(</span><span style="color:#0468D7">C</span><span style="color:#222222">()); </span><span style="color:#6E6E70">// OK.</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Here's a more realistic example using everyday types in Dart like <code>int</code> or <code>num</code>:</p> <?code-excerpt "lib/bounded/instantiate_to_bound.dart (inference-using-bounds-2)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">X</span><span style="color:#6200EE"> max</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">X</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Comparable</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">X</span><span style="color:#222222">>>(</span><span style="color:#0468D7">X</span><span style="color:#222222"> x1, </span><span style="color:#0468D7">X</span><span style="color:#222222"> x2) => x1.</span><span style="color:#6200EE">compareTo</span><span style="color:#222222">(x2) > </span><span style="color:#11796D">0</span><span style="color:#222222"> ? x1 : x2;</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#6E6E70"> // Inferred as `max&#x3C;num>(3, 7)` with the feature, fails without it.</span></span> <span class="line"><span style="color:#6200EE"> max</span><span style="color:#222222">(</span><span style="color:#11796D">3</span><span style="color:#222222">, </span><span style="color:#11796D">7</span><span style="color:#222222">);</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>With inference using bounds, Dart can <em>deconstruct</em> type arguments, extracting type information from a generic type parameter's bound. This allows functions like <code>f</code> in the following example to preserve both the specific iterable type (<code>List</code> or <code>Set</code>) <em>and</em> the element type. Before inference using bounds, this wasn't possible without losing type safety or specific type information.</p><div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#222222">(</span><span style="color:#0468D7">X</span><span style="color:#222222">, </span><span style="color:#0468D7">Y</span><span style="color:#222222">) </span><span style="color:#6200EE">f</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">X</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Iterable</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">Y</span><span style="color:#222222">>, </span><span style="color:#0468D7">Y</span><span style="color:#222222">>(</span><span style="color:#0468D7">X</span><span style="color:#222222"> x) => (x, x.first);</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">void</span><span style="color:#6200EE"> main</span><span style="color:#222222">() {</span></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> (myList, myInt) = </span><span style="color:#6200EE">f</span><span style="color:#222222">([</span><span style="color:#11796D">1</span><span style="color:#222222">]);</span></span> <span class="line"><span style="color:#222222"> myInt.whatever; </span><span style="color:#6E6E70">// Compile-time error, `myInt` has type `int`.</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324"> var</span><span style="color:#222222"> (mySet, myString) = </span><span style="color:#6200EE">f</span><span style="color:#222222">({</span><span style="color:#11796D">'Hello!'</span><span style="color:#222222">});</span></span> <span class="line"><span style="color:#222222"> mySet.</span><span style="color:#6200EE">union</span><span style="color:#222222">({}); </span><span style="color:#6E6E70">// Works, `mySet` has type `Set&#x3C;String>`.</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Without inference using bounds, <code>myInt</code> would have the type <code>dynamic</code>. The previous inference algorithm wouldn't catch the incorrect expression <code>myInt.whatever</code> at compile time, and would instead throw at run time. Conversely, <code>mySet.union({})</code> would be a compile-time error without inference using bounds, because the previous algorithm couldn't preserve the information that <code>mySet</code> is a <code>Set</code>.</p><p>For more information on the inference using bounds algorithm, read the <a href="https://github.com/dart-lang/language/blob/main/accepted/future-releases/3009-inference-using-bounds/design-document.md#motivating-example">design document</a>.</p><div class="header-wrapper"><h2 id="substituting-types">Substituting types</h2><a class="heading-link" href="#substituting-types" aria-label="Link to 'Substituting types' section">#</a></div><p>When you override a method, you are replacing something of one type (in the old method) with something that might have a new type (in the new method). Similarly, when you pass an argument to a function, you are replacing something that has one type (a parameter with a declared type) with something that has another type (the actual argument). When can you replace something that has one type with something that has a subtype or a supertype?</p><p>When substituting types, it helps to think in terms of <em>consumers</em> and <em>producers</em>. A consumer absorbs a type and a producer generates a type.</p><p><strong>You can replace a consumer's type with a supertype and a producer's type with a subtype.</strong></p><p>Let's look at examples of simple type assignment and assignment with generic types.</p><div class="header-wrapper"><h3 id="simple-type-assignment">Simple type assignment</h3><a class="heading-link" href="#simple-type-assignment" aria-label="Link to 'Simple type assignment' section">#</a></div><p>When assigning objects to objects, when can you replace a type with a different type? The answer depends on whether the object is a consumer or a producer.</p><p>Consider the following type hierarchy:</p><img src="/assets/img/language/type-hierarchy.png" alt="a hierarchy of animals where the supertype is Animal and the subtypes are Alligator, Cat, and HoneyBadger. Cat has the subtypes of Lion and MaineCoon"><p>Consider the following simple assignment where <code>Cat c</code> is a <em>consumer</em> and <code>Cat()</code> is a <em>producer</em>:</p> <?code-excerpt "lib/strong_analysis.dart (Cat-Cat-ok)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Cat</span><span style="color:#222222"> c = </span><span style="color:#0468D7">Cat</span><span style="color:#222222">();</span></span></code></pre></div></div><p>In a consuming position, it's safe to replace something that consumes a specific type (<code>Cat</code>) with something that consumes anything (<code>Animal</code>), so replacing <code>Cat c</code> with <code>Animal c</code> is allowed, because <code>Animal</code> is a supertype of <code>Cat</code>.</p> <?code-excerpt "lib/strong_analysis.dart (Animal-Cat-ok)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-passes-sa"><span class="code-block-tag">✔ static analysis: success</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Animal</span><span style="color:#222222"> c = </span><span style="color:#0468D7">Cat</span><span style="color:#222222">();</span></span></code></pre></div></div><p>But replacing <code>Cat c</code> with <code>MaineCoon c</code> breaks type safety, because the superclass may provide a type of Cat with different behaviors, such as <code>Lion</code>:</p> <?code-excerpt "lib/strong_analysis.dart (MaineCoon-Cat-err)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-fails-sa"><span class="code-block-tag">✗ static analysis: failure</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">MaineCoon</span><span style="color:#222222"> c = </span><span style="color:#0468D7">Cat</span><span style="color:#222222">();</span></span></code></pre></div></div><p>In a producing position, it's safe to replace something that produces a type (<code>Cat</code>) with a more specific type (<code>MaineCoon</code>). So, the following is allowed:</p> <?code-excerpt "lib/strong_analysis.dart (Cat-MaineCoon-ok)"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-passes-sa"><span class="code-block-tag">✔ static analysis: success</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">Cat</span><span style="color:#222222"> c = </span><span style="color:#0468D7">MaineCoon</span><span style="color:#222222">();</span></span></code></pre></div></div><div class="header-wrapper"><h3 id="generic-type-assignment">Generic type assignment</h3><a class="heading-link" href="#generic-type-assignment" aria-label="Link to 'Generic type assignment' section">#</a></div><p>Are the rules the same for generic types? Yes. Consider the hierarchy of lists of animals—a <code>List</code> of <code>Cat</code> is a subtype of a <code>List</code> of <code>Animal</code>, and a supertype of a <code>List</code> of <code>MaineCoon</code>:</p><img src="/assets/img/language/type-hierarchy-generics.png" alt="List<Animal> -> List<Cat> -> List<MaineCoon>"><p>In the following example, you can assign a <code>MaineCoon</code> list to <code>myCats</code> because <code>List&lt;MaineCoon&gt;</code> is a subtype of <code>List&lt;Cat&gt;</code>:</p> <?code-excerpt "lib/strong_analysis.dart (generic-type-assignment-MaineCoon)" replace="/<MaineCoon/<[!MaineCoon!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-passes-sa"><span class="code-block-tag">✔ static analysis: success</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><mark class="highlight"><span style="color:#0468D7">MaineCoon</span></mark><span style="color:#222222">> myMaineCoons = ...</span></span> <span class="line"><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">Cat</span><span style="color:#222222">> myCats = myMaineCoons;</span></span></code></pre></div></div><p>What about going in the other direction? Can you assign an <code>Animal</code> list to a <code>List&lt;Cat&gt;</code>?</p> <?code-excerpt "lib/strong_analysis.dart (generic-type-assignment-Animal)" replace="/<Animal/<[!Animal!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-fails-sa"><span class="code-block-tag">✗ static analysis: failure</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><mark class="highlight"><span style="color:#0468D7">Animal</span></mark><span style="color:#222222">> myAnimals = ...</span></span> <span class="line"><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">Cat</span><span style="color:#222222">> myCats = myAnimals;</span></span></code></pre></div></div><p>This assignment doesn't pass static analysis because it creates an implicit downcast, which is disallowed from non-<code>dynamic</code> types such as <code>Animal</code>.</p><p>To make this type of code pass static analysis, you can use an explicit cast.</p> <?code-excerpt "lib/strong_analysis.dart (generic-type-assignment-implied-cast)" replace="/as.*(?=;)/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body"><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">Animal</span><span style="color:#222222">> myAnimals = ...</span></span> <span class="line"><span style="color:#0468D7">List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">Cat</span><span style="color:#222222">> myCats = myAnimals </span><mark class="highlight"><span style="color:#D43324">as</span><span style="color:#0468D7"> List</span><span style="color:#222222">&#x3C;</span><span style="color:#0468D7">Cat</span><span style="color:#222222">></span></mark><span style="color:#222222">;</span></span></code></pre></div></div><p>An explicit cast might still fail at runtime, though, depending on the actual type of the list being cast (<code>myAnimals</code>).</p><div class="header-wrapper"><h3 id="methods">Methods</h3><a class="heading-link" href="#methods" aria-label="Link to 'Methods' section">#</a></div><p>When overriding a method, the producer and consumer rules still apply. For example:</p><img src="/assets/img/language/consumer-producer-methods.png" alt="Animal class showing the chase method as the consumer and the parent getter as the producer"><p>For a consumer (such as the <code>chase(Animal)</code> method), you can replace the parameter type with a supertype. For a producer (such as the <code>parent</code> getter method), you can replace the return type with a subtype.</p><p>For more information, see <a href="#use-proper-return-types">Use sound return types when overriding methods</a> and <a href="#use-proper-param-types">Use sound parameter types when overriding methods</a>.</p><p><a id="covariant-keyword" aria-hidden="true"></a></p><div class="header-wrapper"><h4 id="covariant-parameters">Covariant parameters</h4><a class="heading-link" href="#covariant-parameters" aria-label="Link to 'Covariant parameters' section">#</a></div><p>Some (rarely used) coding patterns rely on tightening a type by overriding a parameter's type with a subtype, which is invalid. In this case, you can use the <code>covariant</code> keyword to tell the analyzer that you're doing this intentionally. This removes the static error and instead checks for an invalid argument type at runtime.</p><p>The following shows how you might use <code>covariant</code>:</p> <?code-excerpt "lib/covariant.dart" replace="/covariant/[!$&!]/g"?> <div class="code-block-wrapper language-dart"><div class="code-block-body has-tag tag-passes-sa"><span class="code-block-tag">✔ static analysis: success</span><span class="code-block-language" title="Language dart">dart</span><pre class="shiki dash-light" tabindex="0"><code><span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Animal</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> chase</span><span style="color:#222222">(</span><span style="color:#0468D7">Animal</span><span style="color:#222222"> x) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Mouse</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Animal</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222">}</span></span> <span class="line"></span> <span class="line"><span style="color:#D43324">class</span><span style="color:#0468D7"> Cat</span><span style="color:#D43324"> extends</span><span style="color:#0468D7"> Animal</span><span style="color:#222222"> {</span></span> <span class="line"><span style="color:#D43324"> @override</span></span> <span class="line"><span style="color:#D43324"> void</span><span style="color:#6200EE"> chase</span><span style="color:#222222">(</span><mark class="highlight"><span style="color:#D43324">covariant</span></mark><span style="color:#0468D7"> Mouse</span><span style="color:#222222"> x) {</span></span> <span class="line"><span style="color:#222222"> ...</span></span> <span class="line"><span style="color:#222222"> }</span></span> <span class="line"><span style="color:#222222">}</span></span></code></pre></div></div><p>Although this example shows using <code>covariant</code> in the subtype, the <code>covariant</code> keyword can be placed in either the superclass or the subclass method. Usually the superclass method is the best place to put it. The <code>covariant</code> keyword applies to a single parameter and is also supported on setters and fields.</p><div class="header-wrapper"><h2 id="other-resources">Other resources</h2><a class="heading-link" href="#other-resources" aria-label="Link to 'Other resources' section">#</a></div><p>The following resources have further information on sound Dart:</p><ul><li><a href="/tools/non-promotion-reasons">Fixing type promotion failures</a> - Understand and learn how to fix type promotion errors.</li><li><a href="/null-safety">Sound null safety</a> - Learn about writing code with sound null safety.</li><li><a href="/tools/analysis">Customizing static analysis</a> - How to set up and customize the analyzer and linter using an analysis options file.</li></ul><nav id="prev-next"><ul><li class="previous"><a href="/language/typedefs">&lang;&nbsp;&nbsp;Typedefs</a></li><li class="next"><a href="/language/patterns">Patterns&nbsp;&nbsp;&rang;</a></li></ul></nav><p id="page-github-links"><span>Unless stated otherwise, the documentation on this site reflects Dart 3.7.2. Page last updated on 2025-03-12.</span> <a href="https://github.com/dart-lang/site-www/tree/main/src/content/language/type-system.md" target="_blank" rel="noopener">View source</a> <span>or </span><a href="https://github.com/dart-lang/site-www/issues/new?template=1_page_issue.yml&page-url=https://dart.dev/language/type-system/&page-source=https://github.com/dart-lang/site-www/tree/main/src/content/language/type-system.md" title="Report an issue with this page" target="_blank" rel="noopener">report an issue</a>.</p></div></article></main></div><footer id="page-footer"><div class="footer-section footer-main"><a href="/" class="brand" title="Dart"><img src="/assets/img/logo/logo-white-text.svg" alt="Dart" width="164"></a><div class="footer-social-links"><a href="https://medium.com/dartlang" target="_blank" rel="noopener" title="Dart's Medium publication"><svg><use href="/assets/img/social/medium.svg#medium"></use></svg> </a><a href="https://github.com/dart-lang" target="_blank" rel="noopener" title="Dart's GitHub organization"><svg><use href="/assets/img/social/github.svg#github"></use></svg> </a><a href="https://bsky.app/profile/dart.dev" target="_blank" rel="noopener" title="Dart's Bluesky profile"><svg><use href="/assets/img/social/bluesky.svg#bluesky"></use></svg> </a><a href="https://twitter.com/dart_lang" target="_blank" rel="noopener" title="Dart's X (Twitter) profile"><svg><use href="/assets/img/social/x.svg#x"></use></svg></a></div></div><div class="footer-section footer-tray"><div class="footer-licenses">Except as otherwise noted, this site is licensed under a <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>, and code samples are licensed under the <a href="https://opensource.org/licenses/BSD-3-Clause">3-Clause BSD License</a>.</div><div class="footer-utility-links"><ul><li><a href="/terms" title="Terms of use">Terms</a></li><li><a href="https://policies.google.com/privacy" target="_blank" rel="noopener" title="Privacy policy">Privacy</a></li><li><a href="/security" title="Security philosophy and practices">Security</a></li></ul></div></div></footer></div></body></html>

Pages: 1 2 3 4 5 6 7 8 9 10