CINXE.COM
TypeScript support in Svelte - Learn web development | MDN
<!doctype html><html lang="en-US" prefix="og: https://ogp.me/ns#"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><link rel="icon" href="https://developer.mozilla.org/favicon-48x48.bc390275e955dacb2e65.png"/><link rel="apple-touch-icon" href="https://developer.mozilla.org/apple-touch-icon.528534bba673c38049c2.png"/><meta name="theme-color" content="#ffffff"/><link rel="manifest" href="https://developer.mozilla.org/manifest.f42880861b394dd4dc9b.json"/><link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="MDN Web Docs"/><title>TypeScript support in Svelte - Learn web development | MDN</title><link rel="alternate" title="TypeScript-Unterstützung in Svelte" href="https://developer.mozilla.org/de/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript" hrefLang="de"/><link rel="alternate" title="Svelte 对 TypeScript 的支持" href="https://developer.mozilla.org/zh-CN/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript" hrefLang="zh"/><link rel="alternate" title="TypeScript support in Svelte" href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript" hrefLang="en"/><link rel="preload" as="font" type="font/woff2" href="/static/media/Inter.var.c2fe3cb2b7c746f7966a.woff2" crossorigin=""/><link rel="alternate" type="application/rss+xml" title="MDN Blog RSS Feed" href="https://developer.mozilla.org/en-US/blog/rss.xml" hrefLang="en"/><meta name="description" content="In the last article we learned about Svelte stores and even implemented our own custom store to persist the app's information to Web Storage. We also had a look at using the transition directive to implement animations on DOM elements in Svelte."/><meta property="og:url" content="https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript"/><meta property="og:title" content="TypeScript support in Svelte - Learn web development | MDN"/><meta property="og:type" content="website"/><meta property="og:locale" content="en_US"/><meta property="og:description" content="In the last article we learned about Svelte stores and even implemented our own custom store to persist the app's information to Web Storage. We also had a look at using the transition directive to implement animations on DOM elements in Svelte."/><meta property="og:image" content="https://developer.mozilla.org/mdn-social-share.d893525a4fb5fb1f67a2.png"/><meta property="og:image:type" content="image/png"/><meta property="og:image:height" content="1080"/><meta property="og:image:width" content="1920"/><meta property="og:image:alt" content="The MDN Web Docs logo, featuring a blue accent color, displayed on a solid black background."/><meta property="og:site_name" content="MDN Web Docs"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:creator" content="MozDevNet"/><link rel="canonical" href="https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript"/><style media="print">.article-actions-container,.document-toc-container,.language-menu,.main-menu-toggle,.on-github,.page-footer,.place,.sidebar,.top-banner,.top-navigation-main,ul.prev-next{display:none!important}.main-page-content,.main-page-content pre{padding:2px}.main-page-content pre{border-left-width:2px}</style><script src="/static/js/gtag.js" defer=""></script><script defer="" src="/static/js/main.f565372a.js"></script><link href="/static/css/main.3d9e7a02.css" rel="stylesheet"/></head><body><script>if(document.body.addEventListener("load",(t=>{t.target.classList.contains("interactive")&&t.target.setAttribute("data-readystate","complete")}),{capture:!0}),window&&document.documentElement){const t={light:"#ffffff",dark:"#1b1b1b"};try{const e=window.localStorage.getItem("theme");e&&(document.documentElement.className=e,document.documentElement.style.backgroundColor=t[e]);const o=window.localStorage.getItem("nop");o&&(document.documentElement.dataset.nop=o)}catch(t){console.warn("Unable to read theme from localStorage",t)}}</script><div id="root"><ul id="nav-access" class="a11y-nav"><li><a id="skip-main" href="#content">Skip to main content</a></li><li><a id="skip-search" href="#top-nav-search-input">Skip to search</a></li><li><a id="skip-select-language" href="#languages-switcher-button">Skip to select language</a></li></ul><div class="page-wrapper category-javascript document-page"><div class="top-banner loading"><section class="place top container"></section></div><div class="sticky-header-container"><header class="top-navigation "><div class="container "><div class="top-navigation-wrap"><a href="/en-US/" class="logo" aria-label="MDN homepage"><svg id="mdn-docs-logo" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 694.9 104.4" style="enable-background:new 0 0 694.9 104.4" xml:space="preserve" role="img"><title>MDN Web Docs</title><path d="M40.3 0 11.7 92.1H0L28.5 0h11.8zm10.4 0v92.1H40.3V0h10.4zM91 0 62.5 92.1H50.8L79.3 0H91zm10.4 0v92.1H91V0h10.4z" class="logo-m"></path><path d="M627.9 95.6h67v8.8h-67v-8.8z" class="logo-_"></path><path d="M367 42h-4l-10.7 30.8h-5.5l-10.8-26h-.4l-10.5 26h-5.2L308.7 42h-3.8v-5.6H323V42h-6.5l6.8 20.4h.4l10.3-26h4.7l11.2 26h.5l5.7-20.3h-6.2v-5.6H367V42zm34.9 20c-.4 3.2-2 5.9-4.7 8.2-2.8 2.3-6.5 3.4-11.3 3.4-5.4 0-9.7-1.6-13.1-4.7-3.3-3.2-5-7.7-5-13.7 0-5.7 1.6-10.3 4.7-14s7.4-5.5 12.9-5.5c5.1 0 9.1 1.6 11.9 4.7s4.3 6.9 4.3 11.3c0 1.5-.2 3-.5 4.7h-25.6c.3 7.7 4 11.6 10.9 11.6 2.9 0 5.1-.7 6.5-2 1.5-1.4 2.5-3 3-4.9l6 .9zM394 51.3c.2-2.4-.4-4.7-1.8-6.9s-3.8-3.3-7-3.3c-3.1 0-5.3 1-6.9 3-1.5 2-2.5 4.4-2.8 7.2H394zm51 2.4c0 5-1.3 9.5-4 13.7s-6.9 6.2-12.7 6.2c-6 0-10.3-2.2-12.7-6.7-.1.4-.2 1.4-.4 2.9s-.3 2.5-.4 2.9h-7.3c.3-1.7.6-3.5.8-5.3.3-1.8.4-3.7.4-5.5V22.3h-6v-5.6H416v27c1.1-2.2 2.7-4.1 4.7-5.7 2-1.6 4.8-2.4 8.4-2.4 4.6 0 8.4 1.6 11.4 4.7 3 3.2 4.5 7.6 4.5 13.4zm-7.7.6c0-4.2-1-7.4-3-9.5-2-2.2-4.4-3.3-7.4-3.3-3.4 0-6 1.2-8 3.7-1.9 2.4-2.9 5-3 7.7V57c0 3 1 5.6 3 7.7s4.5 3.1 7.6 3.1c3.6 0 6.3-1.3 8.1-3.9 1.8-2.7 2.7-5.9 2.7-9.6zm69.2 18.5h-13.2v-7.2c-1.2 2.2-2.8 4.1-4.9 5.6-2.1 1.6-4.8 2.4-8.3 2.4-4.8 0-8.7-1.6-11.6-4.9-2.9-3.2-4.3-7.7-4.3-13.3 0-5 1.3-9.6 4-13.7 2.6-4.1 6.9-6.2 12.8-6.2 5.7 0 9.8 2.2 12.3 6.5V22.3h-8.6v-5.6h15.8v50.6h6v5.5zM493.2 56v-4.4c-.1-3-1.2-5.5-3.2-7.3s-4.4-2.8-7.2-2.8c-3.6 0-6.3 1.3-8.2 3.9-1.9 2.6-2.8 5.8-2.8 9.6 0 4.1 1 7.3 3 9.5s4.5 3.3 7.4 3.3c3.2 0 5.8-1.3 7.8-3.8 2.1-2.6 3.1-5.3 3.2-8zm53.1-1.4c0 5.6-1.8 10.2-5.3 13.7s-8.2 5.3-13.9 5.3-10.1-1.7-13.4-5.1c-3.3-3.4-5-7.9-5-13.5 0-5.3 1.6-9.9 4.7-13.7 3.2-3.8 7.9-5.7 14.2-5.7s11 1.9 14.1 5.7c3 3.7 4.6 8.1 4.6 13.3zm-7.7-.2c0-4-1-7.2-3-9.5s-4.8-3.5-8.2-3.5c-3.6 0-6.4 1.2-8.3 3.7s-2.9 5.6-2.9 9.5c0 3.7.9 6.8 2.8 9.4 1.9 2.6 4.6 3.9 8.3 3.9 3.6 0 6.4-1.3 8.4-3.8 1.9-2.6 2.9-5.8 2.9-9.7zm45 5.8c-.4 3.2-1.9 6.3-4.4 9.1-2.5 2.9-6.4 4.3-11.8 4.3-5.2 0-9.4-1.6-12.6-4.8-3.2-3.2-4.8-7.7-4.8-13.7 0-5.5 1.6-10.1 4.7-13.9 3.2-3.8 7.6-5.7 13.2-5.7 2.3 0 4.6.3 6.7.8 2.2.5 4.2 1.5 6.2 2.9l1.5 9.5-5.9.7-1.3-6.1c-2.1-1.2-4.5-1.8-7.2-1.8-3.5 0-6.1 1.2-7.7 3.7-1.7 2.5-2.5 5.7-2.5 9.6 0 4.1.9 7.3 2.7 9.5 1.8 2.3 4.4 3.4 7.8 3.4 5.2 0 8.2-2.9 9.2-8.8l6.2 1.3zm34.7 1.9c0 3.6-1.5 6.5-4.6 8.5s-7 3-11.7 3c-5.7 0-10.6-1.2-14.6-3.6l1.2-8.8 5.7.6-.2 4.7c1.1.5 2.3.9 3.6 1.1s2.6.3 3.9.3c2.4 0 4.5-.4 6.5-1.3 1.9-.9 2.9-2.2 2.9-4.1 0-1.8-.8-3.1-2.3-3.8s-3.5-1.3-5.8-1.7-4.6-.9-6.9-1.4c-2.3-.6-4.2-1.6-5.7-2.9-1.6-1.4-2.3-3.5-2.3-6.3 0-4.1 1.5-6.9 4.6-8.5s6.4-2.4 9.9-2.4c2.6 0 5 .3 7.2.9 2.2.6 4.3 1.4 6.1 2.4l.8 8.8-5.8.7-.8-5.7c-2.3-1-4.7-1.6-7.2-1.6-2.1 0-3.7.4-5.1 1.1-1.3.8-2 2-2 3.8 0 1.7.8 2.9 2.3 3.6 1.5.7 3.4 1.2 5.7 1.6 2.2.4 4.5.8 6.7 1.4 2.2.6 4.1 1.6 5.7 3 1.4 1.6 2.2 3.7 2.2 6.6zM197.6 73.2h-17.1v-5.5h3.8V51.9c0-3.7-.7-6.3-2.1-7.9-1.4-1.6-3.3-2.3-5.7-2.3-3.2 0-5.6 1.1-7.2 3.4s-2.4 4.6-2.5 6.9v15.6h6v5.5h-17.1v-5.5h3.8V51.9c0-3.8-.7-6.4-2.1-7.9-1.4-1.5-3.3-2.3-5.6-2.3-3.2 0-5.5 1.1-7.2 3.3-1.6 2.2-2.4 4.5-2.5 6.9v15.8h6.9v5.5h-20.2v-5.5h6V42.4h-6.1v-5.6h13.4v6.4c1.2-2.1 2.7-3.8 4.7-5.2 2-1.3 4.4-2 7.3-2s5.3.7 7.5 2.1c2.2 1.4 3.7 3.5 4.5 6.4 1.1-2.5 2.7-4.5 4.9-6.1s4.8-2.4 7.9-2.4c3.5 0 6.5 1.1 8.9 3.3s3.7 5.6 3.7 10.2v18.2h6.1v5.5zm42.5 0h-13.2V66c-1.2 2.2-2.8 4.1-4.9 5.6-2.1 1.6-4.8 2.4-8.3 2.4-4.8 0-8.7-1.6-11.6-4.9-2.9-3.2-4.3-7.7-4.3-13.3 0-5 1.3-9.6 4-13.7 2.6-4.1 6.9-6.2 12.8-6.2s9.8 2.2 12.3 6.5V22.7h-8.6v-5.6h15.8v50.6h6v5.5zm-13.3-16.8V52c-.1-3-1.2-5.5-3.2-7.3s-4.4-2.8-7.2-2.8c-3.6 0-6.3 1.3-8.2 3.9-1.9 2.6-2.8 5.8-2.8 9.6 0 4.1 1 7.3 3 9.5s4.5 3.3 7.4 3.3c3.2 0 5.8-1.3 7.8-3.8 2.1-2.6 3.1-5.3 3.2-8zm61.5 16.8H269v-5.5h6V51.9c0-3.7-.7-6.3-2.2-7.9-1.4-1.6-3.4-2.3-5.7-2.3-3.1 0-5.6 1-7.4 3s-2.8 4.4-2.9 7v15.9h6v5.5h-19.3v-5.5h6V42.4h-6.2v-5.6h13.6V43c2.6-4.6 6.8-6.9 12.7-6.9 3.6 0 6.7 1.1 9.2 3.3s3.7 5.6 3.7 10.2v18.2h6v5.4h-.2z" class="logo-text"></path></svg></a><button title="Open main menu" type="button" class="button action has-icon main-menu-toggle" aria-haspopup="menu" aria-label="Open main menu" aria-expanded="false"><span class="button-wrap"><span class="icon icon-menu "></span><span class="visually-hidden">Open main menu</span></span></button></div><div class="top-navigation-main"><nav class="main-nav" aria-label="Main menu"><ul class="main-menu nojs"><li class="top-level-entry-container "><button type="button" id="references-button" class="top-level-entry menu-toggle" aria-controls="references-menu" aria-expanded="false">References</button><a href="/en-US/docs/Web" class="top-level-entry">References</a><ul id="references-menu" class="submenu references hidden inline-submenu-lg" aria-labelledby="references-button"><li class="apis-link-container mobile-only "><a href="/en-US/docs/Web" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Overview / Web Technology</div><p class="submenu-item-description">Web technology reference for developers</p></div></a></li><li class="html-link-container "><a href="/en-US/docs/Web/HTML" class="submenu-item "><div class="submenu-icon html"></div><div class="submenu-content-container"><div class="submenu-item-heading">HTML</div><p class="submenu-item-description">Structure of content on the web</p></div></a></li><li class="css-link-container "><a href="/en-US/docs/Web/CSS" class="submenu-item "><div class="submenu-icon css"></div><div class="submenu-content-container"><div class="submenu-item-heading">CSS</div><p class="submenu-item-description">Code used to describe document style</p></div></a></li><li class="javascript-link-container "><a href="/en-US/docs/Web/JavaScript" class="submenu-item "><div class="submenu-icon javascript"></div><div class="submenu-content-container"><div class="submenu-item-heading">JavaScript</div><p class="submenu-item-description">General-purpose scripting language</p></div></a></li><li class="http-link-container "><a href="/en-US/docs/Web/HTTP" class="submenu-item "><div class="submenu-icon http"></div><div class="submenu-content-container"><div class="submenu-item-heading">HTTP</div><p class="submenu-item-description">Protocol for transmitting web resources</p></div></a></li><li class="apis-link-container "><a href="/en-US/docs/Web/API" class="submenu-item "><div class="submenu-icon apis"></div><div class="submenu-content-container"><div class="submenu-item-heading">Web APIs</div><p class="submenu-item-description">Interfaces for building web applications</p></div></a></li><li class="apis-link-container "><a href="/en-US/docs/Mozilla/Add-ons/WebExtensions" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Web Extensions</div><p class="submenu-item-description">Developing extensions for web browsers</p></div></a></li><li class=" "><a href="/en-US/docs/Web/Accessibility" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Accessibility</div><p class="submenu-item-description">Build web projects usable for all</p></div></a></li><li class="apis-link-container desktop-only "><a href="/en-US/docs/Web" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Web Technology</div><p class="submenu-item-description">Web technology reference for developers</p></div></a></li></ul></li><li class="top-level-entry-container active"><button type="button" id="learn-button" class="top-level-entry menu-toggle" aria-controls="learn-menu" aria-expanded="false">Learn</button><a href="/en-US/docs/Learn_web_development" class="top-level-entry">Learn</a><ul id="learn-menu" class="submenu learn hidden inline-submenu-lg" aria-labelledby="learn-button"><li class="apis-link-container mobile-only "><a href="/en-US/docs/Learn_web_development" class="submenu-item "><div class="submenu-icon learn"></div><div class="submenu-content-container"><div class="submenu-item-heading">Overview / MDN Learning Area</div><p class="submenu-item-description">Learn web development</p></div></a></li><li class="apis-link-container desktop-only "><a href="/en-US/docs/Learn_web_development" class="submenu-item "><div class="submenu-icon learn"></div><div class="submenu-content-container"><div class="submenu-item-heading">MDN Learning Area</div><p class="submenu-item-description">Learn web development</p></div></a></li><li class="html-link-container "><a href="/en-US/docs/Learn_web_development/Core/Structuring_content" class="submenu-item "><div class="submenu-icon html"></div><div class="submenu-content-container"><div class="submenu-item-heading">HTML</div><p class="submenu-item-description">Learn to structure web content with HTML</p></div></a></li><li class="css-link-container "><a href="/en-US/docs/Learn_web_development/Core/Styling_basics" class="submenu-item "><div class="submenu-icon css"></div><div class="submenu-content-container"><div class="submenu-item-heading">CSS</div><p class="submenu-item-description">Learn to style content using CSS</p></div></a></li><li class="javascript-link-container "><a href="/en-US/docs/Learn_web_development/Core/Scripting" class="submenu-item "><div class="submenu-icon javascript"></div><div class="submenu-content-container"><div class="submenu-item-heading">JavaScript</div><p class="submenu-item-description">Learn to run scripts in the browser</p></div></a></li><li class=" "><a href="/en-US/docs/Learn_web_development/Core/Accessibility" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Accessibility</div><p class="submenu-item-description">Learn to make the web accessible to all</p></div></a></li></ul></li><li class="top-level-entry-container "><button type="button" id="mdn-plus-button" class="top-level-entry menu-toggle" aria-controls="mdn-plus-menu" aria-expanded="false">Plus</button><a href="/en-US/plus" class="top-level-entry">Plus</a><ul id="mdn-plus-menu" class="submenu mdn-plus hidden inline-submenu-lg" aria-labelledby="mdn-plus-button"><li class=" "><a href="/en-US/plus" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Overview</div><p class="submenu-item-description">A customized MDN experience</p></div></a></li><li class=" "><a href="/en-US/plus/ai-help" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">AI Help</div><p class="submenu-item-description">Get real-time assistance and support</p></div></a></li><li class=" "><a href="/en-US/plus/updates" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Updates</div><p class="submenu-item-description">All browser compatibility updates at a glance</p></div></a></li><li class=" "><a href="/en-US/plus/docs/features/overview" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Documentation</div><p class="submenu-item-description">Learn how to use MDN Plus</p></div></a></li><li class=" "><a href="/en-US/plus/docs/faq" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">FAQ</div><p class="submenu-item-description">Frequently asked questions about MDN Plus</p></div></a></li></ul></li><li class="top-level-entry-container "><a class="top-level-entry menu-link" href="/en-US/curriculum/">Curriculum <sup class="new">New</sup></a></li><li class="top-level-entry-container "><a class="top-level-entry menu-link" href="/en-US/blog/">Blog</a></li><li class="top-level-entry-container "><button type="button" id="tools-button" class="top-level-entry menu-toggle" aria-controls="tools-menu" aria-expanded="false">Tools</button><ul id="tools-menu" class="submenu tools hidden inline-submenu-lg" aria-labelledby="tools-button"><li class=" "><a href="/en-US/play" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">Playground</div><p class="submenu-item-description">Write, test and share your code</p></div></a></li><li class=" "><a href="/en-US/observatory" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">HTTP Observatory</div><p class="submenu-item-description">Scan a website for free</p></div></a></li><li class=" "><a href="/en-US/plus/ai-help" class="submenu-item "><div class="submenu-icon"></div><div class="submenu-content-container"><div class="submenu-item-heading">AI Help</div><p class="submenu-item-description">Get real-time assistance and support</p></div></a></li></ul></li></ul></nav><div class="header-search"><form action="/en-US/search" class="search-form search-widget" id="top-nav-search-form" role="search"><label id="top-nav-search-label" for="top-nav-search-input" class="visually-hidden">Search MDN</label><input aria-activedescendant="" aria-autocomplete="list" aria-controls="top-nav-search-menu" aria-expanded="false" aria-labelledby="top-nav-search-label" autoComplete="off" id="top-nav-search-input" role="combobox" type="search" class="search-input-field" name="q" placeholder=" " required="" value=""/><button type="button" class="button action has-icon clear-search-button"><span class="button-wrap"><span class="icon icon-cancel "></span><span class="visually-hidden">Clear search input</span></span></button><button type="submit" class="button action has-icon search-button"><span class="button-wrap"><span class="icon icon-search "></span><span class="visually-hidden">Search</span></span></button><div id="top-nav-search-menu" role="listbox" aria-labelledby="top-nav-search-label"></div></form></div><div class="theme-switcher-menu"><button type="button" class="button action has-icon theme-switcher-menu small" aria-haspopup="menu"><span class="button-wrap"><span class="icon icon-theme-os-default "></span>Theme</span></button></div><ul class="auth-container"><li><a href="/users/fxa/login/authenticate/?next=%2Fen-US%2Fdocs%2FLearn_web_development%2FCore%2FFrameworks_libraries%2FSvelte_TypeScript" class="login-link" rel="nofollow">Log in</a></li><li><a href="/users/fxa/login/authenticate/?next=%2Fen-US%2Fdocs%2FLearn_web_development%2FCore%2FFrameworks_libraries%2FSvelte_TypeScript" target="_self" rel="nofollow" class="button primary mdn-plus-subscribe-link"><span class="button-wrap">Sign up for free</span></a></li></ul></div></div></header><div class="article-actions-container"><div class="container"><button type="button" class="button action has-icon sidebar-button" aria-label="Expand sidebar" aria-expanded="false" aria-controls="sidebar-quicklinks"><span class="button-wrap"><span class="icon icon-sidebar "></span></span></button><nav class="breadcrumbs-container" aria-label="Breadcrumb"><ol typeof="BreadcrumbList" vocab="https://schema.org/" aria-label="breadcrumbs"><li property="itemListElement" typeof="ListItem"><a href="/en-US/docs/Learn_web_development" class="breadcrumb" property="item" typeof="WebPage"><span property="name">Learn</span></a><meta property="position" content="1"/></li><li property="itemListElement" typeof="ListItem"><a href="/en-US/docs/Learn_web_development/Core" class="breadcrumb" property="item" typeof="WebPage"><span property="name">Core learning modules</span></a><meta property="position" content="2"/></li><li property="itemListElement" typeof="ListItem"><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries" class="breadcrumb" property="item" typeof="WebPage"><span property="name">JavaScript frameworks and libraries</span></a><meta property="position" content="3"/></li><li property="itemListElement" typeof="ListItem"><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript" class="breadcrumb-current-page" property="item" typeof="WebPage"><span property="name">TypeScript support in Svelte</span></a><meta property="position" content="4"/></li></ol></nav><div class="article-actions"><button type="button" class="button action has-icon article-actions-toggle" aria-label="Article actions"><span class="button-wrap"><span class="icon icon-ellipses "></span><span class="article-actions-dialog-heading">Article Actions</span></span></button><ul class="article-actions-entries"><li class="article-actions-entry"><div class="languages-switcher-menu open-on-focus-within"><button id="languages-switcher-button" type="button" class="button action small has-icon languages-switcher-menu" aria-haspopup="menu"><span class="button-wrap"><span class="icon icon-language "></span>English (US)</span></button><div class="hidden"><ul class="submenu language-menu " aria-labelledby="language-menu-button"><li class=" "><form class="submenu-item locale-redirect-setting"><div class="group"><label class="switch"><input type="checkbox" name="locale-redirect"/><span class="slider"></span><span class="label">Remember language</span></label><a href="https://github.com/orgs/mdn/discussions/739" rel="external noopener noreferrer" target="_blank" title="Enable this setting to automatically switch to this language when it's available. (Click to learn more.)"><span class="icon icon-question-mark "></span></a></div></form></li><li class=" "><a data-locale="de" href="/de/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript" class="button submenu-item"><span>Deutsch</span><span title="Diese Übersetzung ist Teil eines Experiments."><span class="icon icon-experimental "></span></span></a></li><li class=" "><a data-locale="zh-CN" href="/zh-CN/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript" class="button submenu-item"><span>中文 (简体)</span></a></li></ul></div></div></li></ul></div></div></div></div><div class="main-wrapper"><div class="sidebar-container"><aside id="sidebar-quicklinks" class="sidebar"><button type="button" class="button action backdrop" aria-label="Collapse sidebar"><span class="button-wrap"></span></button><nav aria-label="Related Topics" class="sidebar-inner"><header class="sidebar-actions"><section class="sidebar-filter-container"><div class="sidebar-filter "><label id="sidebar-filter-label" class="sidebar-filter-label" for="sidebar-filter-input"><span class="icon icon-filter"></span><span class="visually-hidden">Filter sidebar</span></label><input id="sidebar-filter-input" autoComplete="off" class="sidebar-filter-input-field false" type="text" placeholder="Filter" value=""/><button type="button" class="button action has-icon clear-sidebar-filter-button"><span class="button-wrap"><span class="icon icon-cancel "></span><span class="visually-hidden">Clear filter input</span></span></button></div></section></header><div class="sidebar-inner-nav"><div class="in-nav-toc"><div class="document-toc-container"><section class="document-toc"><header><h2 class="document-toc-heading">In this article</h2></header><ul class="document-toc-list"><li class="document-toc-item "><a class="document-toc-link" href="#code_along_with_us">Code along with us</a></li><li class="document-toc-item "><a class="document-toc-link" href="#typescript_optional_static_typing_for_javascript">TypeScript: optional static typing for JavaScript</a></li><li class="document-toc-item "><a class="document-toc-link" href="#why_typescript">Why TypeScript?</a></li><li class="document-toc-item "><a class="document-toc-link" href="#creating_a_svelte_typescript_project_from_scratch">Creating a Svelte TypeScript project from scratch</a></li><li class="document-toc-item "><a class="document-toc-link" href="#adding_typescript_support_to_an_existing_svelte_project">Adding TypeScript support to an existing Svelte Project</a></li><li class="document-toc-item "><a class="document-toc-link" href="#improved_developer_experience_with_typescript">Improved developer experience with TypeScript</a></li><li class="document-toc-item "><a class="document-toc-link" href="#creating_a_custom_type">Creating a custom type</a></li><li class="document-toc-item "><a class="document-toc-link" href="#porting_our_to-do_list_app_to_typescript">Porting our to-do list app to TypeScript</a></li><li class="document-toc-item "><a class="document-toc-link" href="#bulletproofing_our_stores_with_generics">Bulletproofing our stores with Generics</a></li><li class="document-toc-item "><a class="document-toc-link" href="#the_code_so_far">The code so far</a></li><li class="document-toc-item "><a class="document-toc-link" href="#summary">Summary</a></li></ul></section></div></div><div class="sidebar-body"><ol><li class="section"><a href="/en-US/docs/Learn_web_development/Getting_started">Getting started modules</a></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup">Environment setup</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Installing_software">Installing basic software</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Browsing_the_web">Browsing the web</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Code_editors">Code editors</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Dealing_with_files">Dealing with files</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Command_line">Command line crash course</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Getting_started/Your_first_website">Your first website</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Getting_started/Your_first_website/What_will_your_website_look_like">What will your website look like?</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Creating_the_content">HTML: Creating the content</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Styling_the_content">CSS: Styling the content</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Adding_interactivity">JavaScript: Adding interactivity</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Publishing_your_website">Publishing your website</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Getting_started/Web_standards">Web standards</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Getting_started/Web_standards/How_the_web_works">How the web works</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Web_standards/The_web_standards_model">The web standards model</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Web_standards/How_browsers_load_websites">How browsers load websites</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Getting_started/Soft_skills">Soft skills</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Research_and_learning">Research and learning</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Collaboration_and_teamwork">Collaboration and teamwork</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Workflows_and_processes">Workflows and processes</a></li><li><a href="/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Job_interviews">Succeeding in job interviews</a></li></ol></details></li><li class="section"><a href="/en-US/docs/Learn_web_development/Core">Core modules</a></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Core/Structuring_content">Structuring content with HTML</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Basic_HTML_syntax">Basic HTML syntax</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Webpage_metadata">What's in the head? Webpage metadata</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Headings_and_paragraphs">Headings and paragraphs in HTML</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Emphasis_and_importance">Emphasis and importance</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Lists">Lists</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Structuring_documents">Structuring documents</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Advanced_text_features">Advanced text features</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Creating_links">Creating links</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Marking_up_a_letter">Challenge: Marking up a letter</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Structuring_a_page_of_content">Challenge: Structuring a page of content</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_images">HTML images</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_video_and_audio">HTML video and audio</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Mozilla_splash_page">Challenge: Mozilla splash page</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_table_basics">HTML table basics</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Table_accessibility">HTML table accessibility</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Planet_data_table">Challenge: Structuring a planet data table</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_forms">Forms and buttons in HTML</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Structuring_content/Debugging_HTML">Debugging HTML</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Core/Styling_basics">CSS styling basics</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/What_is_CSS">What is CSS?</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Getting_started">Getting started with CSS</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Styling_a_bio_page">Challenge: Styling a biography page</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Basic_selectors">Basic CSS selectors</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Attribute_selectors">Attribute selectors</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Pseudo_classes_and_elements">Pseudo-classes and pseudo-elements</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Combinators">Combinators</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Box_model">The box model</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Handling_conflicts">Handling conflicts</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Values_and_units">CSS values and units</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Sizing">Sizing items in CSS</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Backgrounds_and_borders">Backgrounds and borders</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Overflow">Overflowing content</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Images_media_forms">Images, media, and form elements</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Tables">Styling tables</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Debugging_CSS">Debugging CSS</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Fundamental_CSS_comprehension">Challenge: Fundamental CSS comprehension</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Fancy_letterheaded_paper">Challenge: Creating fancy letterheaded paper</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Styling_basics/Cool-looking_box">Challenge: A cool-looking box</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Core/Text_styling">CSS text styling</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/Text_styling/Fundamentals">Fundamental text and font styling</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Text_styling/Styling_lists">Styling lists</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Text_styling/Styling_links">Styling links</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Text_styling/Web_fonts">Web fonts</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Text_styling/Typesetting_a_homepage">Challenge: Typesetting a community school homepage</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Core/CSS_layout">CSS layout</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Introduction">Introduction to CSS layout</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Floats">Floats</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Positioning">Positioning</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Flexbox">Flexbox</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Grids">CSS grid layout</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Responsive_Design">Responsive design</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Media_queries">Media query fundamentals</a></li><li><a href="/en-US/docs/Learn_web_development/Core/CSS_layout/Fundamental_Layout_Comprehension">Challenge: Fundamental layout comprehension</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Core/Scripting">Dynamic scripting with JavaScript</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/What_is_JavaScript">What is JavaScript?</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/A_first_splash">A first splash into JavaScript</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/What_went_wrong">What went wrong? Troubleshooting JavaScript</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Variables">Storing the information you need — Variables</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Math">Basic math in JavaScript — numbers and operators</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Strings">Handling text — strings in JavaScript</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Useful_string_methods">Useful string methods</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Arrays">Arrays</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Silly_story_generator">Challenge: Silly story generator</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Conditionals">Making decisions in your code — conditionals</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Loops">Looping code</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Functions">Functions — reusable blocks of code</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Build_your_own_function">Build your own function</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Return_values">Function return values</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Events">Introduction to events</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Event_bubbling">Event bubbling</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Image_gallery">Challenge: Image gallery</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Object_basics">JavaScript object basics</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/DOM_scripting">DOM scripting introduction</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Network_requests">Making network requests with JavaScript</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/JSON">Working with JSON</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Scripting/Debugging_JavaScript">Debugging JavaScript and handling errors</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries">JavaScript frameworks and libraries</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Introduction">Introduction to client-side frameworks</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Main_features">Framework main features</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_getting_started">Getting started with React</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_todo_list_beginning">Beginning our React todo list</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_components">Componentizing our React app</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_events_state">React interactivity: Events and state</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_filtering_conditional_rendering">React interactivity: Editing, filtering, conditional rendering</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility">Accessibility in React</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_resources">React resources</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Core/Accessibility">Accessibility</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/What_is_accessibility">What is accessibility?</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/Tooling">Accessibility tooling and assistive technology</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/HTML">HTML: A good basis for accessibility</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/CSS_and_JavaScript">CSS and JavaScript accessibility best practices</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/WAI-ARIA_basics">WAI-ARIA basics</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/Multimedia">Accessible multimedia</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/Mobile">Mobile accessibility</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Accessibility/Accessibility_troubleshooting">Challenge: Accessibility troubleshooting</a></li></ol></details></li><li><a href="/en-US/docs/Learn_web_development/Core/Design_for_developers">Design for developers</a></li><li><a href="/en-US/docs/Learn_web_development/Core/Version_control">Version control</a></li><li class="section"><a href="/en-US/docs/Learn_web_development/Extensions">Extension modules</a></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects">Advanced JavaScript objects</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_prototypes">Object prototypes</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object-oriented_programming">Object-oriented programming</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Classes_in_JavaScript">Classes in JavaScript</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_building_practice">Object building practice</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Adding_bouncing_balls_features">Challenge: Adding features to our bouncing balls demo</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_APIs">Client-side web APIs</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Introduction">Introduction to web APIs</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Video_and_audio_APIs">Video and Audio APIs</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Drawing_graphics">Drawing graphics</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage">Client-side storage</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Third_party_APIs">Third-party APIs</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Async_JS">Asynchronous JavaScript</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Async_JS/Introducing">Introducing asynchronous JavaScript</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Async_JS/Promises">How to use promises</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Async_JS/Implementing_a_promise-based_API">How to implement a promise-based API</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Async_JS/Introducing_workers">Introducing workers</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Async_JS/Sequencing_animations">Challenge: Sequencing animations</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Forms">Web forms</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Your_first_form">Your first form</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/How_to_structure_a_web_form">How to structure a web form</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Basic_native_form_controls">Basic native form controls</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/HTML5_input_types">The HTML5 input types</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Other_form_controls">Other form controls</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Styling_web_forms">Styling web forms</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Advanced_form_styling">Advanced form styling</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/UI_pseudo-classes">UI pseudo-classes</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Form_validation">Client-side form validation</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Forms/Sending_and_retrieving_form_data">Sending form data</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_tools">Understanding client-side tools</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Overview">Client-side tooling overview</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Package_management">Package management basics</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Introducing_complete_toolchain">Introducing a complete toolchain</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Deployment">Deploying our app</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Server-side">Server-side websites</a></summary><ol><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps">Server-side first steps</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Introduction">Introduction to the server side</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Client-Server_overview">Client-Server Overview</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Web_frameworks">Server-side web frameworks</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Website_security">Website security</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django">Django web framework (Python)</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Introduction">Django introduction</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/development_environment">Setting up a Django development environment</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Tutorial_local_library_website">Django Tutorial: The Local Library website</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/skeleton_website">Django Tutorial Part 2: Creating a skeleton website</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Models">Django Tutorial Part 3: Using models</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Admin_site">Django Tutorial Part 4: Django admin site</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Home_page">Django Tutorial Part 5: Creating our home page</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Generic_views">Django Tutorial Part 6: Generic list and detail views</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Sessions">Django Tutorial Part 7: Sessions framework</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Authentication">Django Tutorial Part 8: User authentication and permissions</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Forms">Django Tutorial Part 9: Working with forms</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Testing">Django Tutorial Part 10: Testing a Django web application</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Deployment">Django Tutorial Part 11: Deploying Django to production</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/web_application_security">Django web application security</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Django/django_assessment_blog">Assessment: DIY Django mini blog</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs">Express web framework (Node.js)</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/development_environment">Setting up a Node development environment</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li></ol></details></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Performance">Web performance</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/why_web_performance">The "why" of web performance</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/What_is_web_performance">What is web performance?</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/Perceived_performance">Perceived performance</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/Measuring_performance">Measuring performance</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/Multimedia">Multimedia: Images</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/video">Multimedia: video</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/JavaScript">JavaScript performance optimization</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/HTML">HTML performance optimization</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/CSS">CSS performance optimization</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Performance/business_case_for_performance">The business case for web performance</a></li></ol></details></li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Extensions/Testing">Testing</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Extensions/Testing/Introduction">Introduction to cross-browser testing</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Testing/Testing_strategies">Strategies for carrying out testing</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Testing/HTML_and_CSS">Handling common HTML and CSS problems</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection">Implementing feature detection</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Testing/Automated_testing">Introduction to automated testing</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Testing/Your_own_automation_environment">Setting up your own test automation environment</a></li></ol></details></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Transform_animate">Transform and animate CSS</a></li><li><a href="/en-US/docs/Learn_web_development/Extensions/Security_privacy">Security and privacy</a></li><li class="section">Further resources</li><li class="toggle"><details><summary><a href="/en-US/docs/Learn_web_development/Howto">How to solve common problems</a></summary><ol><li><a href="/en-US/docs/Learn_web_development/Howto/Solve_HTML_problems">Solve common HTML problems</a></li><li><a href="/en-US/docs/Learn_web_development/Howto/Solve_CSS_problems">Solve common CSS problems</a></li><li><a href="/en-US/docs/Learn_web_development/Howto/Solve_JavaScript_problems">Solve common JavaScript problems</a></li><li><a href="/en-US/docs/Learn_web_development/Howto/Web_mechanics">Web mechanics</a></li><li><a href="/en-US/docs/Learn_web_development/Howto/Tools_and_setup">Tools and setup</a></li><li><a href="/en-US/docs/Learn_web_development/Howto/Design_and_accessibility">Design and accessibility</a></li></ol></details></li><li><a href="/en-US/docs/Learn_web_development/About">About</a></li><li><a href="/en-US/docs/Learn_web_development/Educators">Resources for educators</a></li><li><a href="/en-US/docs/Learn_web_development/Changelog">Changelog</a></li></ol></div></div><section class="place side"></section></nav></aside><div class="toc-container"><aside class="toc"><nav><div class="document-toc-container"><section class="document-toc"><header><h2 class="document-toc-heading">In this article</h2></header><ul class="document-toc-list"><li class="document-toc-item "><a class="document-toc-link" href="#code_along_with_us">Code along with us</a></li><li class="document-toc-item "><a class="document-toc-link" href="#typescript_optional_static_typing_for_javascript">TypeScript: optional static typing for JavaScript</a></li><li class="document-toc-item "><a class="document-toc-link" href="#why_typescript">Why TypeScript?</a></li><li class="document-toc-item "><a class="document-toc-link" href="#creating_a_svelte_typescript_project_from_scratch">Creating a Svelte TypeScript project from scratch</a></li><li class="document-toc-item "><a class="document-toc-link" href="#adding_typescript_support_to_an_existing_svelte_project">Adding TypeScript support to an existing Svelte Project</a></li><li class="document-toc-item "><a class="document-toc-link" href="#improved_developer_experience_with_typescript">Improved developer experience with TypeScript</a></li><li class="document-toc-item "><a class="document-toc-link" href="#creating_a_custom_type">Creating a custom type</a></li><li class="document-toc-item "><a class="document-toc-link" href="#porting_our_to-do_list_app_to_typescript">Porting our to-do list app to TypeScript</a></li><li class="document-toc-item "><a class="document-toc-link" href="#bulletproofing_our_stores_with_generics">Bulletproofing our stores with Generics</a></li><li class="document-toc-item "><a class="document-toc-link" href="#the_code_so_far">The code so far</a></li><li class="document-toc-item "><a class="document-toc-link" href="#summary">Summary</a></li></ul></section></div></nav></aside><section class="place side"></section></div></div><main id="content" class="main-content "><article class="main-page-content" lang="en-US"><header><h1>TypeScript support in Svelte</h1></header><div class="section-content"><ul class="prev-next"><li><a class="button secondary" href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_stores"><span class="button-wrap"> Previous </span></a></li><li><a class="button secondary" href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries"><span class="button-wrap"> Overview: JavaScript frameworks and libraries</span></a></li><li><a class="button secondary" href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_deployment_next"><span class="button-wrap"> Next </span></a></li></ul> <p>In the last article we learned about Svelte stores and even implemented our own custom store to persist the app's information to Web Storage. We also had a look at using the transition directive to implement animations on DOM elements in Svelte.</p> <p>We will now learn how to use TypeScript in Svelte applications. First we'll learn what TypeScript is and what benefits it can bring us. Then we'll see how to configure our project to work with TypeScript files. Finally we will go over our app and see what modifications we have to make to fully take advantage of TypeScript features.</p> <figure class="table-container"><table> <tbody> <tr> <th scope="row">Prerequisites:</th> <td> <p> At minimum, it is recommended that you are familiar with the core <a href="/en-US/docs/Learn_web_development/Core/Structuring_content">HTML</a>, <a href="/en-US/docs/Learn_web_development/Core/Styling_basics">CSS</a>, and <a href="/en-US/docs/Learn_web_development/Core/Scripting">JavaScript</a> languages, and have knowledge of the <a href="/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Command_line">terminal/command line</a>. </p> <p> You'll need a terminal with node and npm installed to compile and build your app. </p> </td> </tr> <tr> <th scope="row">Objective:</th> <td> Learn how to configure and use TypeScript when developing Svelte applications. </td> </tr> </tbody> </table></figure> <p>Note that our application is fully functional, and porting it to TypeScript is completely optional. There are different opinions about it, and in this chapter we will talk briefly about the pros and cons of using TypeScript. Even if you are not planning to adopt it, this article will be useful for allowing you to learn what it has to offer and help you make your own decision. If you are not interested at all in TypeScript, you can skip to the next chapter, where we will look at different options for deploying our Svelte applications, further resources, and more.</p></div><section aria-labelledby="code_along_with_us"><h2 id="code_along_with_us"><a href="#code_along_with_us">Code along with us</a></h2><div class="section-content"></div></section><section aria-labelledby="git"><h3 id="git"><a href="#git">Git</a></h3><div class="section-content"><p>Clone the GitHub repo (if you haven't already done it) with:</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>git clone https://github.com/opensas/mdn-svelte-tutorial.git </code></pre></div> <p>Then to get to the current app state, run</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>cd mdn-svelte-tutorial/07-typescript-support </code></pre></div> <p>Or directly download the folder's content:</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>npx degit opensas/mdn-svelte-tutorial/07-typescript-support </code></pre></div> <p>Remember to run <code>npm install && npm run dev</code> to start your app in development mode.</p></div></section><section aria-labelledby="repl"><h3 id="repl"><a href="#repl">REPL</a></h3><div class="section-content"><p>Unfortunately, <a href="https://github.com/sveltejs/sites/issues/156" class="external" target="_blank">TypeScript support is not yet available in the REPL</a>.</p></div></section><section aria-labelledby="typescript_optional_static_typing_for_javascript"><h2 id="typescript_optional_static_typing_for_javascript"><a href="#typescript_optional_static_typing_for_javascript">TypeScript: optional static typing for JavaScript</a></h2><div class="section-content"><p><a href="https://www.typescriptlang.org/" class="external" target="_blank">TypeScript</a> is a superset of JavaScript that provides features such as optional static typing, classes, interfaces, and generics. The goal of TypeScript is to help catch mistakes early through its type system and make JavaScript development more efficient. One of the big benefits is enabling IDEs to provide a richer environment for spotting common errors as you type the code.</p> <p>Best of all, JavaScript code is valid TypeScript code; TypeScript is a superset of JavaScript. You can rename most of your <code>.js</code> files to <code>.ts</code> files and they will just work.</p> <p>Our TypeScript code will be able to run everywhere JavaScript can run. How is that possible? TypeScript "transpiles" our code to vanilla JavaScript. That means that it parses TypeScript code and produces the equivalent vanilla JavaScript code for browsers to run.</p> <div class="notecard note"> <p><strong>Note:</strong> If you are curious about how TypeScript transpiles our code to JavaScript, you can have a look at the <a href="https://www.typescriptlang.org/play/?target=1&e=4#example/hello-world" class="external" target="_blank">TypeScript Playground</a>.</p> </div> <p>First-class TypeScript support has been Svelte's most requested feature for quite some time. Thanks to the hard work of the Svelte team, together with many contributors, they have an <a href="https://svelte.dev/blog/svelte-and-typescript" class="external" target="_blank">official solution</a> ready to be put to the test. In this section we'll show you how to set up a Svelte project with TypeScript support to give it a try.</p></div></section><section aria-labelledby="why_typescript"><h2 id="why_typescript"><a href="#why_typescript">Why TypeScript?</a></h2><div class="section-content"><p>TypeScript's main advantages are:</p> <ul> <li>Early spotted bugs: The compiler checks types at compile time and provides error reporting.</li> <li>Readability: Static typing gives the code more structure, making it self-documenting and more readable.</li> <li>Rich IDE support: Type information allows code editors and IDEs to offer features like code navigation, autocompletion, and smarter hints.</li> <li>Safer refactoring: Types allows IDEs to know more about your code, and assist you while refactoring large portions of your code base.</li> <li>Type inference: Enables you to take advantage of many TypeScript features even without declaring variable types.</li> <li>Availability of new and future JavaScript features: TypeScript transpiles many recent JavaScript features to plain old-school JavaScript, allowing you to use them even on user-agents that don't support them natively yet.</li> </ul> <p>TypeScript also has some disadvantages:</p> <ul> <li>Not true static typing: Types are only checked at compile time, and they are removed from the generated code.</li> <li>Steep learning curve: Even though TypeScript is a superset of JavaScript and not a completely new language, there is a considerable learning curve, especially if you have no experience at all with static languages like Java or C#.</li> <li>More code: You have to write and maintain more code.</li> <li>No replacement for automatic tests: Even though types might help you catch several bugs, TypeScript is not a true replacement for a comprehensive suite of automated tests.</li> <li>Boilerplate code: Working with types, classes, interfaces, and generics can lead to over-engineered code bases.</li> </ul> <p>There seems to be a broad consensus that TypeScript is particularly well suited for large-scale projects, with many developers working on the same codebase. And it is indeed being used by several large-scale projects, like Angular 2, Vue 3, Ionic, Visual Studio Code, Jest, and even the Svelte compiler. Nevertheless, some developers prefer to use it even on small projects like the one we are developing.</p> <p>In the end, it's your decision. In the following sections we hope to give you more evidence to make up your mind about it.</p></div></section><section aria-labelledby="creating_a_svelte_typescript_project_from_scratch"><h2 id="creating_a_svelte_typescript_project_from_scratch"><a href="#creating_a_svelte_typescript_project_from_scratch">Creating a Svelte TypeScript project from scratch</a></h2><div class="section-content"><p>You can start a new Svelte TypeScript project using the <a href="https://github.com/sveltejs/template" class="external" target="_blank">standard template</a>. All you have to do is run the following terminal commands (run them somewhere where you are storing your Svelte test projects — it creates a new directory):</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>npx degit sveltejs/template svelte-typescript-app cd svelte-typescript-app node scripts/setupTypeScript.js </code></pre></div> <p>This creates a starter project that includes TypeScript support, which you can then modify as you wish.</p> <p>Then you'll have to tell npm to download dependencies and start the project in development mode, as we usually do:</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>npm install npm run dev </code></pre></div></div></section><section aria-labelledby="adding_typescript_support_to_an_existing_svelte_project"><h2 id="adding_typescript_support_to_an_existing_svelte_project"><a href="#adding_typescript_support_to_an_existing_svelte_project">Adding TypeScript support to an existing Svelte Project</a></h2><div class="section-content"><p>To add TypeScript support to an existing Svelte project, you can <a href="https://svelte.dev/blog/svelte-and-typescript#Adding_TypeScript_to_an_existing_project" class="external" target="_blank">follow these instructions</a>. Alternatively, you can download the <a href="https://github.com/sveltejs/template/blob/master/scripts/setupTypeScript.js" class="external" target="_blank"><code>setupTypeScript.js</code></a> file to a <code>scripts</code> folder inside your project's root folder, and then run <code>node scripts/setupTypeScript.js</code>.</p> <p>You can even use <code>degit</code> to download the script. That's what we will do to start porting our application to TypeScript.</p> <div class="notecard note"> <p><strong>Note:</strong> Remember that you can run <code>npx degit opensas/mdn-svelte-tutorial/07-typescript-support svelte-todo-typescript</code> to get the complete to-do list application in JavaScript before you start porting it to TypeScript.</p> </div> <p>Go to the root directory of the project and enter these commands:</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>npx degit sveltejs/template/scripts scripts # download script file to a scripts folder node scripts/setupTypeScript.js # run it # Converted to TypeScript. </code></pre></div> <p>You will need to re-run your dependency manager to get started.</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>npm install # download new dependencies npm run dev # start the app in development mode </code></pre></div> <p>These instructions apply to any Svelte project you'd like to convert to TypeScript. Just take into account that the Svelte community is constantly improving Svelte TypeScript support, so you should run <code>npm update</code> regularly to take advantage of the latest changes.</p> <div class="notecard note"> <p><strong>Note:</strong> If you find any trouble working with TypeScript inside a Svelte application, have a look at this <a href="https://github.com/sveltejs/language-tools/blob/master/docs/preprocessors/typescript.md#troubleshooting--faq" class="external" target="_blank">troubleshooting/FAQ section about TypeScript support</a>.</p> </div> <p>As we said before, TypeScript is a superset of JavaScript, so your application will run without modifications. Currently you will be running a regular JavaScript application with TypeScript support enabled, without taking advantage of any of the features that TypeScript provides. You can now start adding types progressively.</p> <p>Once you have TypeScript configured, you can start using it from a Svelte component by just adding a <code><script lang='ts'></code> at the beginning of the script section. To use it from regular JavaScript files, just change the file extension from <code>.js</code> to <code>.ts</code>. You'll also have to update any corresponding import statements to remove the <code>.ts</code> file extension from all <code>import</code> statements.</p> <div class="notecard note"> <p><strong>Note:</strong> TypeScript will throw an error if you use the <code>.ts</code> file extension in an <code>import</code> statement, so you if you have a file <code>./foo.ts</code>, you must import it as "./foo". See the <a href="https://www.typescriptlang.org/docs/handbook/modules/theory.html#module-resolution-for-bundlers-typescript-runtimes-and-nodejs-loaders" class="external" target="_blank">Module resolution for bundlers, TypeScript runtimes, and Node.js loaders</a> section of the TypeScript manual for more information.</p> </div> <div class="notecard note"> <p><strong>Note:</strong> Using TypeScript in component markup sections is not supported in Svelte 4, which this guide is based on. So while you can use JavaScript from the markup, you'll have to use TypeScript in the <code><script lang='ts'></code> section. TypeScript in component markup is allowed from Svelte 5.</p> </div></div></section><section aria-labelledby="improved_developer_experience_with_typescript"><h2 id="improved_developer_experience_with_typescript"><a href="#improved_developer_experience_with_typescript">Improved developer experience with TypeScript</a></h2><div class="section-content"><p>TypeScript provides code editors and IDEs with lots of information to allow them to deliver a friendlier development experience.</p> <p>We'll use <a href="https://code.visualstudio.com/" class="external" target="_blank">Visual Studio Code</a> to do a quick test and see how we can get autocompletion hints and type-checking as we're writing components.</p> <div class="notecard note"> <p><strong>Note:</strong> If you don't wish to use VS Code, we also provide instructions for using TypeScript error checking from the terminal instead, slightly later on.</p> </div> <p>There is work in progress to support TypeScript in Svelte projects in several code editors; the most complete support so far is available in the <a href="https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode" class="external" target="_blank">Svelte for VS Code extension</a>, which is developed and maintained by the Svelte team. This extension offers type checking, inspecting, refactoring, intellisense, hover-information, auto-completion, and other features. This kind of developer assistance is another good reason to start using TypeScript in your projects.</p> <div class="notecard note"> <p><strong>Note:</strong> Make sure you are using <a href="https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode" class="external" target="_blank">Svelte for VS Code</a> and NOT the old "Svelte" by James Birtles, which has been discontinued. In case you have it installed, you should uninstall it and install the official Svelte extension instead.</p> </div> <p>Assuming you are inside the VS Code application, from the root of your project's folder, type <code>code .</code> (the trailing dot tells VS Code to open the current folder) to open the code editor. VS Code will tell you that there are recommended extensions to install.</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/01-vscode-extension-recommendations.png" alt="Dialog box saying this workspace has extension recommendations, with options to install or show a list" width="475" height="108" loading="lazy"></p> <p>Clicking <em>Install all</em> will install Svelte for VS Code.</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/02-svelte-for-vscode.png" alt="Svelte for VS Code extension information" width="1043" height="210" loading="lazy"></p> <p>We can also see that the <code>setupTypeScript.js</code> file made a couple of changes to our project. The <code>main.js</code> file has been renamed to <code>main.ts</code>, which means that VS Code can provide hover-information on our Svelte components:</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/03-vscode-hints-in-main-ts.png" alt="VS Code screenshot showing that when hovering on a component, it gives you hints" width="480" height="287" loading="lazy"></p> <!-- cSpell:ignore traget --> <p>We also get type checking for free. If we pass an unknown property in the options parameter of the <code>App</code> constructor (for example a typo like <code>traget</code> instead of <code>target</code>), TypeScript will complain:</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/04-vscode-type-checking-in-main-ts.png" alt="Type checking in VS Code - App object has been given an unknown property traget" width="895" height="277" loading="lazy"></p> <p>In the <code>App.svelte</code> component, the <code>setupTypeScript.js</code> script has added the <code>lang="ts"</code> attribute to the <code><script></code> tag. Moreover, thanks to type inference, in many cases we won't even need to specify types to get code assistance. For example, if you start adding an <code>ms</code> property to the <code>Alert</code> component call, TypeScript will infer from the default value that the <code>ms</code> property should be a number:</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/05-vscode-type-inference-and-code-assistance.png" alt="VS Code type inference and code hinting - ms variable should be a number" width="842" height="387" loading="lazy"></p> <p>And if you pass something that is not a number, it will complain about it:</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/06-vscode-type-checking-in-components.png" alt="Type checking in VS Code - the ms variable has been given a non-numeric value" width="678" height="236" loading="lazy"></p> <p>The application template has a <code>check</code> script configured that runs <code>svelte-check</code> against your code. This package allows you to detect errors and warnings normally displayed by a code editor from the command line, which makes it pretty useful for running it in a continuous integration (CI) pipeline. Just run <code>npm run check</code> to check for unused CSS, and return A11y hints and TypeScript compile errors.</p> <p>In this case, if you run <code>npm run check</code> (either in the VS Code console or terminal) you will get the following error:</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/07-vscode-svelte-check.png" alt="Check command being run inside VS Code showing type error, ms variable should be assigned a number" width="753" height="480" loading="lazy"></p> <p>Even better, if you run it from the VS Code integrated terminal (you can open it with the <kbd>Ctrl</kbd> + <kbd>`</kbd> keyboard shortcut), <kbd>Cmd</kbd>/<kbd>Ctrl</kbd> clicking on the file name will take you to the line containing the error.</p> <p>You can also run the <code>check</code> script in watch mode with <code>npm run check -- --watch</code>. In this case, the script will execute whenever you change any file. If you are running this in your regular terminal, keep it running in the background in a separate terminal window so that it can keep reporting errors but won't interfere with other terminal usage.</p></div></section><section aria-labelledby="creating_a_custom_type"><h2 id="creating_a_custom_type"><a href="#creating_a_custom_type">Creating a custom type</a></h2><div class="section-content"><p>TypeScript supports structural typing. Structural typing is a way of relating types based solely on their members, even if you do not explicitly define the type.</p> <p>We'll define a <code>TodoType</code> type to see how TypeScript enforces that anything passed to a component expecting a <code>TodoType</code> will be structurally compatible with it.</p> <ol> <li> <p>Inside the <code>src</code> folder create a <code>types</code> folder.</p> </li> <li> <p>Add a <code>todo.type.ts</code> file inside it.</p> </li> <li> <p>Give <code>todo.type.ts</code> the following content:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>export type TodoType = { id: number; name: string; completed: boolean; }; </code></pre></div> <div class="notecard note"> <p><strong>Note:</strong> The Svelte template uses <a href="https://github.com/sveltejs/svelte-preprocess" class="external" target="_blank">svelte-preprocess</a> 4.0.0 to support TypeScript. From that version onward you have to use <code>export</code>/<code>import</code> type syntax to import types and interfaces. Check <a href="https://github.com/sveltejs/language-tools/blob/master/docs/preprocessors/typescript.md#how-do-i-import-interfaces-into-my-svelte-components-i-get-errors-after-transpilation" class="external" target="_blank">this section of the troubleshooting guide</a> for more information.</p> </div> </li> <li> <p>Now we'll use <code>TodoType</code> from our <code>Todo.svelte</code> component. First add the <code>lang="ts"</code> to our <code><script></code> tag.</p> </li> <li> <p>Let's <code>import</code> the type and use it to declare the <code>todo</code> property. Replace the <code>export let todo</code> line with the following:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>import type { TodoType } from "../types/todo.type"; export let todo: TodoType; </code></pre></div> <p>Note that the <code>.ts</code> file extension is not allowed in the <code>import</code> statement, and has been omitted.</p> </li> <li> <p>Now from <code>Todos.svelte</code> we will instantiate a <code>Todo</code> component with a literal object as its parameter before the call to the <code>MoreActions</code> component, like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">svelte</span></div><pre class="brush: svelte notranslate"><code><hr /> <Todo todo={ { name: 'a new task with no id!', completed: false } } /> <!-- MoreActions --> <MoreActions {todos} </code></pre></div> </li> <li> <p>Add the <code>lang='ts'</code> to the <code><script></code> tag of the <code>Todos.svelte</code> component so that it knows to use the type checking we have specified.</p> <p>We will get the following error:</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/08-vscode-structural-typing.png" alt="Type error in VS Code, Todo Type object requires an id property." width="996" height="208" loading="lazy"></p> </li> </ol> <p>By now you should get an idea about the kind of assistance we can get from TypeScript when building Svelte projects.</p> <p>Now we will undo these changes in order to start porting our application to TypeScript, so we won't be bothered with all the check warnings.</p> <ol> <li>Remove the flawed to-do and the <code>lang='ts'</code> attribute from the <code>Todos.svelte</code> file.</li> <li>Also remove the import of <code>TodoType</code> and the <code>lang='ts'</code> from <code>Todo.svelte</code>.</li> </ol> <p>We'll take care of them properly later on.</p></div></section><section aria-labelledby="porting_our_to-do_list_app_to_typescript"><h2 id="porting_our_to-do_list_app_to_typescript"><a href="#porting_our_to-do_list_app_to_typescript">Porting our to-do list app to TypeScript</a></h2><div class="section-content"><p>Now we are ready to start porting our to-do list application to take advantage of all the features that TypeScript offers to us.</p> <p>Let's start by running the check script in watch mode inside the project root:</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>npm run check -- --watch </code></pre></div> <p>This should output something like the following:</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>svelte-check "--watch" Loading svelte-check in workspace: ./svelte-todo-typescript Getting Svelte diagnostics... ==================================== svelte-check found no errors and no warnings </code></pre></div> <p>Note that if you are using a supporting code editor like VS Code, a simple way to start porting a Svelte component is to just add the <code><script lang='ts'></code> at the top of your component and look for the three-dotted hints:</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/09-vscode-alert-hints.png" alt="VS Code screenshot showing that when you add type="ts" to a component, it gives you three dot alert hints" width="903" height="372" loading="lazy"></p></div></section><section aria-labelledby="alert.svelte"><h3 id="alert.svelte"><a href="#alert.svelte">Alert.svelte</a></h3><div class="section-content"><p>Let's start with our <code>Alert.svelte</code> component.</p> <ol> <li> <p>Add <code>lang="ts"</code> into your <code>Alert.svelte</code> component's <code><script></code> tag. You'll see some warnings in the output of the <code>check</code> script:</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>npm run check -- --watch </code></pre></div> <pre class="brush: plain notranslate">> svelte-check "--watch" ./svelte-todo-typescript Getting Svelte diagnostics... ==================================== ./svelte-todo-typescript/src/components/Alert.svelte:8:7 Warn: Variable 'visible' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) let visible ./svelte-todo-typescript/src/components/Alert.svelte:9:7 Warn: Variable 'timeout' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) let timeout ./svelte-todo-typescript/src/components/Alert.svelte:11:28 Warn: Parameter 'message' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) Change = (message, ms) => { ./svelte-todo-typescript/src/components/Alert.svelte:11:37 Warn: Parameter 'ms' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) (message, ms) => { </pre> </li> <li> <p>You can fix these by specifying the corresponding types, like so:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>export let ms = 3000 let visible: boolean let timeout: number const onMessageChange = (message: string, ms: number) => { clearTimeout(timeout) if (!message) { // hide Alert if message is empty </code></pre></div> <div class="notecard note"> <p><strong>Note:</strong> There's no need to specify the <code>ms</code> type with <code>export let ms:number = 3000</code>, because TypeScript is already inferring it from its default value.</p> </div> </li> </ol></div></section><section aria-labelledby="moreactions.svelte"><h3 id="moreactions.svelte"><a href="#moreactions.svelte">MoreActions.svelte</a></h3><div class="section-content"><p>Now we'll do the same for the <code>MoreActions.svelte</code> component.</p> <ol> <li> <p>Add the <code>lang='ts'</code> attribute, like before. TypeScript will warn us about the <code>todos</code> prop and the <code>t</code> variable in the call to <code>todos.filter((t) =>...)</code>.</p> <pre class="brush: plain notranslate">Warn: Variable 'todos' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) export let todos Warn: Parameter 't' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) $: completedTodos = todos.filter((t) => t.completed).length </pre> </li> <li> <p>We will use the <code>TodoType</code> we already defined to tell TypeScript that <code>todos</code> is a <code>TodoType</code> array. Replace the <code>export let todos</code> line with the following:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>import type { TodoType } from "../types/todo.type"; export let todos: TodoType[]; </code></pre></div> </li> </ol> <p>Notice that now TypeScript can infer that the <code>t</code> variable in <code>todos.filter((t) => t.completed)</code> is of type <code>TodoType</code>. Nevertheless, if we think it makes our code easier to read, we could specify it like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>$: completedTodos = todos.filter((t: TodoType) => t.completed).length; </code></pre></div> <p>Most of the time, TypeScript will be able to correctly infer the reactive variable type, but sometimes you might get an "implicitly has an 'any' type" error when working with reactive assignments. In those cases you can declare the typed variable in a different statement, like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>let completedTodos: number; $: completedTodos = todos.filter((t: TodoType) => t.completed).length; </code></pre></div> <p>You can't specify the type in the reactive assignment itself. The statement <code>$: completedTodos: number = todos.filter[...]</code> is invalid. For more information, read <a href="https://github.com/sveltejs/language-tools/blob/master/docs/preprocessors/typescript.md#how-do-i-type-reactive-assignments--i-get-an-implicitly-has-type-any-error" class="external" target="_blank">How do I type reactive assignments? / I get an "implicitly has type 'any' error"</a>.</p></div></section><section aria-labelledby="filterbutton.svelte"><h3 id="filterbutton.svelte"><a href="#filterbutton.svelte">FilterButton.svelte</a></h3><div class="section-content"><p>Now we'll take care of the <code>FilterButton</code> component.</p> <ol> <li> <p>Add the <code>lang='ts'</code> attribute to the <code><script></code> tag, as usual. You'll notice there are no warnings — TypeScript infers the type of the filter variable from the default value. But we know that there are only three valid values for the filter: all, active, and completed. So we can let TypeScript know about them by creating an enum Filter.</p> </li> <li> <p>Create a <code>filter.enum.ts</code> file in the <code>types</code> folder.</p> </li> <li> <p>Give it the following contents:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>export enum Filter { ALL = "all", ACTIVE = "active", COMPLETED = "completed", } </code></pre></div> </li> <li> <p>Now we will use this from the <code>FilterButton</code> component. Replace the content of the <code>FilterButton.svelte</code> file with the following:</p> <div class="code-example"><div class="example-header"><span class="language-name">svelte</span></div><pre class="brush: svelte notranslate"><code><!-- components/FilterButton.svelte --> <script lang="ts"> import { Filter } from "../types/filter.enum"; export let filter: Filter = Filter.ALL; </script> <div class="filters btn-group stack-exception"> <button class="btn toggle-btn" class:btn__primary={filter === Filter.ALL} aria-pressed={filter === Filter.ALL} on:click={()=> filter = Filter.ALL} > <span class="visually-hidden">Show</span> <span>All</span> <span class="visually-hidden">tasks</span> </button> <button class="btn toggle-btn" class:btn__primary={filter === Filter.ACTIVE} aria-pressed={filter === Filter.ACTIVE} on:click={()=> filter = Filter.ACTIVE} > <span class="visually-hidden">Show</span> <span>Active</span> <span class="visually-hidden">tasks</span> </button> <button class="btn toggle-btn" class:btn__primary={filter === Filter.COMPLETED} aria-pressed={filter === Filter.COMPLETED} on:click={()=> filter = Filter.COMPLETED} > <span class="visually-hidden">Show</span> <span>Completed</span> <span class="visually-hidden">tasks</span> </button> </div> </code></pre></div> </li> </ol> <p>Here we are just importing the <code>Filter</code> enum and using it instead of the string values we used previously.</p></div></section><section aria-labelledby="todos.svelte"><h3 id="todos.svelte"><a href="#todos.svelte">Todos.svelte</a></h3><div class="section-content"><p>We will also use the <code>Filter</code> enum in the <code>Todos.svelte</code> component.</p> <ol> <li> <p>First, add the <code>lang='ts'</code> attribute to it, as before.</p> </li> <li> <p>Next, import the <code>Filter</code> enum. Add the following <code>import</code> statement below your existing ones:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>import { Filter } from "../types/filter.enum"; </code></pre></div> </li> <li> <p>Now we will use it whenever we reference the current filter. Replace your two filter-related blocks with the following:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>let filter: Filter = Filter.ALL; const filterTodos = (filter: Filter, todos) => filter === Filter.ACTIVE ? todos.filter((t) => !t.completed) : filter === Filter.COMPLETED ? todos.filter((t) => t.completed) : todos; $: { if (filter === Filter.ALL) { $alert = "Browsing all todos"; } else if (filter === Filter.ACTIVE) { $alert = "Browsing active todos"; } else if (filter === Filter.COMPLETED) { $alert = "Browsing completed todos"; } } </code></pre></div> </li> <li> <p><code>check</code> will still give us some warnings from <code>Todos.svelte</code>. Let's fix them.</p> <p>Start by importing the <code>TodoType</code> and telling TypeScript that our <code>todos</code> variable is an array of <code>TodoType</code>. Replace <code>export let todos = []</code> with the following two lines:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>import type { TodoType } from "../types/todo.type"; export let todos: TodoType[] = []; </code></pre></div> </li> <li> <p>Next we'll specify all the missing types. The variable <code>todosStatus</code>, which we used to programmatically access the methods exposed by the <code>TodosStatus</code> component, is of type <code>TodosStatus</code>. And each <code>todo</code> will be of type <code>TodoType</code>.</p> <p>Update your <code><script></code> section to look like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>import FilterButton from "./FilterButton.svelte"; import Todo from "./Todo.svelte"; import MoreActions from "./MoreActions.svelte"; import NewTodo from "./NewTodo.svelte"; import TodosStatus from "./TodosStatus.svelte"; import { alert } from "../stores"; import { Filter } from "../types/filter.enum"; import type { TodoType } from "../types/todo.type"; export let todos: TodoType[] = []; let todosStatus: TodosStatus; // reference to TodosStatus instance $: newTodoId = todos.length > 0 ? Math.max(...todos.map((t) => t.id)) + 1 : 1; function addTodo(name: string) { todos = [...todos, { id: newTodoId, name, completed: false }]; $alert = `Todo '${name}' has been added`; } function removeTodo(todo: TodoType) { todos = todos.filter((t) => t.id !== todo.id); todosStatus.focus(); // give focus to status heading $alert = `Todo '${todo.name}' has been deleted`; } function updateTodo(todo: TodoType) { const i = todos.findIndex((t) => t.id === todo.id); if (todos[i].name !== todo.name) $alert = `todo '${todos[i].name}' has been renamed to '${todo.name}'`; if (todos[i].completed !== todo.completed) $alert = `todo '${todos[i].name}' marked as ${ todo.completed ? "completed" : "active" }`; todos[i] = { ...todos[i], ...todo }; } let filter: Filter = Filter.ALL; const filterTodos = (filter: Filter, todos: TodoType[]) => filter === Filter.ACTIVE ? todos.filter((t) => !t.completed) : filter === Filter.COMPLETED ? todos.filter((t) => t.completed) : todos; $: { if (filter === Filter.ALL) { $alert = "Browsing all todos"; } else if (filter === Filter.ACTIVE) { $alert = "Browsing active todos"; } else if (filter === Filter.COMPLETED) { $alert = "Browsing completed todos"; } } const checkAllTodos = (completed: boolean) => { todos = todos.map((t) => ({ ...t, completed })); $alert = `${completed ? "Checked" : "Unchecked"} ${todos.length} todos`; }; const removeCompletedTodos = () => { $alert = `Removed ${todos.filter((t) => t.completed).length} todos`; todos = todos.filter((t) => !t.completed); }; </code></pre></div> </li> </ol></div></section><section aria-labelledby="todosstatus.svelte"><h3 id="todosstatus.svelte"><a href="#todosstatus.svelte">TodosStatus.svelte</a></h3><div class="section-content"><p>We are encountering the following errors related to passing <code>todos</code> to the <code>TodosStatus.svelte</code> (and <code>Todo.svelte</code>) components:</p> <pre class="brush: plain notranslate">./src/components/Todos.svelte:70:39 Error: Type 'TodoType[]' is not assignable to type 'undefined'. (ts) <TodosStatus bind:this={todosStatus} {todos} /> ./src/components/Todos.svelte:76:12 Error: Type 'TodoType' is not assignable to type 'undefined'. (ts) <Todo {todo} </pre> <p>This is because the <code>todos</code> prop in the <code>TodosStatus</code> component has no default value, so TypeScript has inferred it to be of type <code>undefined</code>, which is not compatible with an array of <code>TodoType</code>. The same thing is happening with our Todo component.</p> <p>Let's fix it.</p> <ol> <li> <p>Open the file <code>TodosStatus.svelte</code> and add the <code>lang='ts'</code> attribute.</p> </li> <li> <p>Then import the <code>TodoType</code> and declare the <code>todos</code> prop as an array of <code>TodoType</code>. Replace the first line of the <code><script></code> section with the following:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>import type { TodoType } from "../types/todo.type"; export let todos: TodoType[]; </code></pre></div> </li> <li> <p>We will also specify the <code>headingEl</code>, which we used to bind to the heading tag, as an <code>HTMLElement</code>. Update the <code>let headingEl</code> line with the following:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>let headingEl: HTMLElement; </code></pre></div> </li> <li> <p>Finally, you'll notice the following error reported, related to where we set the <code>tabindex</code> attribute. That's because TypeScript is type checking the <code><h2></code> element and expects <code>tabindex</code> to be of type <code>number</code>.</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/10-vscode-tabindex-hint.png" alt="Tabindex hint inside VS Code, tabindex expects a type of number, not string" width="938" height="215" loading="lazy"></p> <p>To fix it, replace <code>tabindex="-1"</code> with <code>tabindex={-1}</code>, like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">svelte</span></div><pre class="brush: svelte notranslate"><code><h2 id="list-heading" bind:this={headingEl} tabindex={-1}> {completedTodos} out of {totalTodos} items completed </h2> </code></pre></div> <p>This way TypeScript can prevent us from incorrectly assigning it to a string variable.</p> </li> </ol></div></section><section aria-labelledby="newtodo.svelte"><h3 id="newtodo.svelte"><a href="#newtodo.svelte">NewTodo.svelte</a></h3><div class="section-content"><p>Next we will take care of <code>NewTodo.svelte</code>.</p> <ol> <li> <p>As usual, add the <code>lang='ts'</code> attribute.</p> </li> <li> <p>The warning will indicate that we have to specify a type for the <code>nameEl</code> variable. Set its type to <code>HTMLElement</code> like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>let nameEl: HTMLElement; // reference to the name input DOM node </code></pre></div> </li> <li> <p>Last for this file, we need to specify the correct type for our <code>autofocus</code> variable. Update its definition like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>export let autofocus: boolean = false; </code></pre></div> </li> </ol></div></section><section aria-labelledby="todo.svelte"><h3 id="todo.svelte"><a href="#todo.svelte">Todo.svelte</a></h3><div class="section-content"><p>Now the only warnings that <code>npm run check</code> emits are triggered by calling the <code>Todo.svelte</code> component. Let's fix them.</p> <ol> <li> <p>Open the <code>Todo.svelte</code> file, and add the <code>lang='ts'</code> attribute.</p> </li> <li> <p>Let's import the <code>TodoType</code>, and set the type of the <code>todo</code> prop. Replace the <code>export let todo</code> line with the following:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>import type { TodoType } from "../types/todo.type"; export let todo: TodoType; </code></pre></div> </li> <li> <p>The first warning we get is TypeScript telling us to define the type of the <code>update()</code> function's <code>updatedTodo</code> variable. This can be a little tricky because <code>updatedTodo</code> contains only the attributes of the <code>todo</code> that have been updated. That means it's not a complete <code>todo</code> — it only has a subset of a <code>todo</code>'s properties.</p> <p>For these kinds of cases, TypeScript provides several <a href="https://www.typescriptlang.org/docs/handbook/utility-types.html" class="external" target="_blank">utility types</a> to make it easier to apply these common transformations. What we need right now is the <a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#partialt" class="external" target="_blank"><code>Partial<T></code></a> utility, which allows us to represent all subsets of a given type. The partial utility returns a new type based on the type <code>T</code>, where every property of <code>T</code> is optional.</p> <p>We'll use it in the <code>update()</code> function — update yours like so:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>function update(updatedTodo: Partial<TodoType>) { todo = { ...todo, ...updatedTodo }; // applies modifications to todo dispatch("update", todo); // emit update event } </code></pre></div> <p>With this we are telling TypeScript that the <code>updatedTodo</code> variable will hold a subset of the <code>TodoType</code> properties.</p> </li> <li> <p>Now svelte-check tells us that we have to define the type of our action function parameters:</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>./07-next-steps/src/components/Todo.svelte:45:24 Warn: Parameter 'node' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) const focusOnInit = (node) => node && typeof node.focus === 'function' && node.focus() ./07-next-steps/src/components/Todo.svelte:47:28 Warn: Parameter 'node' implicitly has an 'any' type, but a better type may be inferred from usage. (ts) const focusEditButton = (node) => editButtonPressed && node.focus() </code></pre></div> <p>We just have to define the node variable to be of type <code>HTMLElement</code>. In the two lines indicated above, replace the first instance of <code>node</code> with <code>node: HTMLElement</code>.</p> </li> </ol></div></section><section aria-labelledby="actions.js"><h3 id="actions.js"><a href="#actions.js">actions.js</a></h3><div class="section-content"><p>Next we'll take care of the <code>actions.js</code> file.</p> <ol> <li> <p>Rename it to <code>actions.ts</code> and add the type of the node parameter. It should end up looking like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>// actions.ts export function selectOnFocus(node: HTMLInputElement) { if (node && typeof node.select === "function") { // make sure node is defined and has a select() method const onFocus = () => node.select(); // event handler node.addEventListener("focus", onFocus); // when node gets focus call onFocus() return { destroy: () => node.removeEventListener("focus", onFocus), // this will be executed when the node is removed from the DOM }; } } </code></pre></div> </li> <li> <p>Now update <code>Todo.svelte</code> and <code>NewTodo.svelte</code> where we import the actions file. Remember that imports in TypeScript don't include the file extension. In each case it should end up like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>import { selectOnFocus } from "../actions"; </code></pre></div> </li> </ol></div></section><section aria-labelledby="migrating_the_stores_to_typescript"><h3 id="migrating_the_stores_to_typescript"><a href="#migrating_the_stores_to_typescript">Migrating the stores to TypeScript</a></h3><div class="section-content"><p>Now we have to migrate the <code>stores.js</code> and <code>localStore.js</code> files to TypeScript.</p> <p>Tip: the script <code>npm run check</code>, which uses the <a href="https://github.com/sveltejs/language-tools/tree/master/packages/svelte-check" class="external" target="_blank"><code>svelte-check</code></a> tool, will only check our application's <code>.svelte</code> files. If you want to also check the <code>.ts</code> files, you can run <code>npm run check && npx tsc --noEmit</code>, which tells the TypeScript compiler to check for errors without generating the <code>.js</code> output files. You could even add a script to your <code>package.json</code> file that runs that command.</p> <p>We'll start with <code>stores.js</code>.</p> <ol> <li> <p>Rename the file to <code>stores.ts</code>.</p> </li> <li> <p>Set the type of our <code>initialTodos</code> array to <code>TodoType[]</code>. This is how the contents will end up:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>// stores.ts import { writable } from "svelte/store"; import { localStore } from "./localStore.js"; import type { TodoType } from "./types/todo.type"; export const alert = writable("Welcome to the To-Do list app!"); const initialTodos: TodoType[] = [ { id: 1, name: "Visit MDN web docs", completed: true }, { id: 2, name: "Complete the Svelte Tutorial", completed: false }, ]; export const todos = localStore("mdn-svelte-todo", initialTodos); </code></pre></div> </li> <li> <p>Remember to update the <code>import</code> statements in <code>App.svelte</code>, <code>Alert.svelte</code>, and <code>Todos.svelte</code>. Just remove the <code>.js</code> extension, like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>import { todos } from "../stores"; </code></pre></div> </li> </ol> <p>Now onto <code>localStore.js</code>.</p> <p>Update the <code>import</code> statement in <code>stores.ts</code> like so:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>import { localStore } from "./localStore"; </code></pre></div> <ol> <li> <p>Start by renaming the file to <code>localStore.ts</code>.</p> </li> <li> <p>TypeScript is telling us to specify the type of the <code>key</code>, <code>initial</code>, and <code>value</code> variables. The first one is easy: the key of our local web storage should be a string.</p> <p>But <code>initial</code> and <code>value</code> should be any object that could be converted to a valid JSON string with the <a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify"><code>JSON.stringify</code></a> method, meaning any JavaScript object with a couple limitations: for example, <code>undefined</code>, functions, and symbols are not valid JSON values.</p> <p>So we'll create the type <code>JsonValue</code> to specify these conditions.</p> <p>Create the file <code>json.type.ts</code> in the <code>types</code> folder.</p> </li> <li> <p>Give it the following content:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>export type JsonValue = | string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue }; </code></pre></div> <p>The <code>|</code> operator lets us declare variables that could store values of two or more types. A <code>JsonValue</code> could be a string, a number, a boolean, and so on. In this case we are also making use of recursive types to specify that a <code>JsonValue</code> can have an array of <code>JsonValue</code> and also an object with properties of type <code>JsonValue</code>.</p> </li> <li> <p>We will import our <code>JsonValue</code> type and use it accordingly. Update your <code>localStore.ts</code> file like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>// localStore.ts import { writable } from "svelte/store"; import type { JsonValue } from "./types/json.type"; export const localStore = (key: string, initial: JsonValue) => { // receives the key of the local storage and an initial value const toString = (value: JsonValue) => JSON.stringify(value, null, 2); // helper function const toObj = JSON.parse; // helper function if (localStorage.getItem(key) === null) { // item not present in local storage localStorage.setItem(key, toString(initial)); // initialize local storage with initial value } const saved = toObj(localStorage.getItem(key)); // convert to object const { subscribe, set, update } = writable(saved); // create the underlying writable store return { subscribe, set: (value: JsonValue) => { localStorage.setItem(key, toString(value)); // save also to local storage as a string return set(value); }, update, }; }; </code></pre></div> </li> </ol> <p>Now if we try to create a <code>localStore</code> with something that cannot be converted to JSON via <code>JSON.stringify()</code>, for example an object with a function as a property, VS Code/<code>validate</code> will complain about it:</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/11-vscode-invalid-store.png" alt="VS Code showing an error with using our store — it fails when trying to set a local storage value to something incompatible with JSON stringify" width="1314" height="236" loading="lazy"></p> <p>And best of all, it will even work with the <a href="https://svelte.dev/docs/svelte-components#script-4-prefix-stores-with-$-to-access-their-values" class="external" target="_blank"><code>$store</code> auto-subscription syntax</a>. If we try to save an invalid value to our <code>todos</code> store using the <code>$store</code> syntax, like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">svelte</span></div><pre class="brush: svelte notranslate"><code><!-- App.svelte --> <script lang="ts"> import Todos from "./components/Todos.svelte"; import Alert from "./components/Alert.svelte"; import { todos } from "./stores"; // this is invalid, the content cannot be converted to JSON using JSON.stringify $todos = { handler: () => {} }; </script> </code></pre></div> <p>The check script will report the following error:</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>> npm run check Getting Svelte diagnostics... ==================================== ./svelte-todo-typescript/src/App.svelte:8:12 Error: Argument of type '{ handler: () => void; }' is not assignable to parameter of type 'JsonValue'. Types of property 'handler' are incompatible. Type '() => void' is not assignable to type 'JsonValue'. Type '() => void' is not assignable to type '{ [key: string]: JsonValue; }'. Index signature is missing in type '() => void'. (ts) $todos = { handler: () => {} } </code></pre></div> <p>This is another example of how specifying types can make our code more robust and help us catch more bugs before they get into production.</p> <p>And that's it. We've converted our whole application to use TypeScript.</p></div></section><section aria-labelledby="bulletproofing_our_stores_with_generics"><h2 id="bulletproofing_our_stores_with_generics"><a href="#bulletproofing_our_stores_with_generics">Bulletproofing our stores with Generics</a></h2><div class="section-content"><p>Our stores have already been ported to TypeScript, but we can do better. We shouldn't need to store any kind of value — we know that the alert store should contain string messages, and the to-dos store should contain an array of <code>TodoType</code>, etc. We can let TypeScript enforce this using <a href="https://www.typescriptlang.org/docs/handbook/generics.html" class="external" target="_blank">TypeScript Generics</a>. Let's find out more.</p></div></section><section aria-labelledby="understanding_typescript_generics"><h3 id="understanding_typescript_generics"><a href="#understanding_typescript_generics">Understanding TypeScript generics</a></h3><div class="section-content"><p>Generics allow you to create reusable code components that work with a variety of types instead of a single type. They can be applied to interfaces, classes, and functions. Generic types are passed as parameters using a special syntax: they are specified within angle brackets and are conventionally denoted with a single uppercase letter. Generic types allow you to capture the types provided by the user, ensuring they're available for future processing.</p> <p>Let's see a quick example, a simple <code>Stack</code> class that lets us <code>push</code> and <code>pop</code> elements, like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>export class Stack { private elements = []; push = (element) => this.elements.push(element); pop() { if (this.elements.length === 0) throw new Error("The stack is empty!"); return this.elements.pop(); } } </code></pre></div> <p>In this case <code>elements</code> is an array of type <code>any</code>, and accordingly the <code>push()</code> and <code>pop()</code> methods both receive and return a variable of type <code>any</code>. So it's perfectly valid to do something like the following:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>const anyStack = new Stack(); anyStack.push(1); anyStack.push("hello"); </code></pre></div> <p>But what if we wanted to have a <code>Stack</code> that would only work with type <code>string</code>? We could do the following:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>export class StringStack { private elements: string[] = []; push = (element: string) => this.elements.push(element); pop(): string { if (this.elements.length === 0) throw new Error("The stack is empty!"); return this.elements.pop(); } } </code></pre></div> <p>That would work. But if we wanted to work with numbers, we would then have to duplicate our code and create a <code>NumberStack</code> class. And how could we handle a stack of types we don't know yet, and that should be defined by the consumer?</p> <p>To solve all these problems, we can use generics.</p> <p>This is our <code>Stack</code> class reimplemented using generics:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>export class Stack<T> { private elements: T[] = []; push = (element: T): number => this.elements.push(element); pop(): T { if (this.elements.length === 0) throw new Error("The stack is empty!"); return this.elements.pop(); } } </code></pre></div> <p>We define a generic type <code>T</code> and then use it like we would normally use a specific type. Now elements is an array of type <code>T</code>, and <code>push()</code> and <code>pop()</code> both receive and return a variable of type <code>T</code>.</p> <p>This is how we would use our generic <code>Stack</code>:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>const numberStack = new Stack<number>(); numberStack.push(1); </code></pre></div> <p>Now TypeScript knows that our stack can only accept numbers, and will issue an error if we try to push anything else:</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/12-vscode-generic-stack-error.png" alt="Argument of type hello is not assignable to parameter of type number" width="849" height="232" loading="lazy"></p> <p>TypeScript can also infer generic types by its usage. Generics also support default values and constraints.</p> <p>Generics are a powerful feature that allows our code to abstract away from the specific types being used, making it more reusable and generic without giving up on type safety. To learn more about it, check out the <a href="https://www.typescriptlang.org/docs/handbook/generics.html" class="external" target="_blank">TypeScript Introduction to Generics</a>.</p></div></section><section aria-labelledby="using_svelte_stores_with_generics"><h3 id="using_svelte_stores_with_generics"><a href="#using_svelte_stores_with_generics">Using Svelte stores with generics</a></h3><div class="section-content"><p>Svelte stores support generics out of the box. And, because of generic type inference, we can take advantage of it without even touching our code.</p> <p>If you open the file <code>Todos.svelte</code> and assign a <code>number</code> type to our <code>$alert</code> store, you'll get the following error:</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/13-vscode-generic-alert-error.png" alt="Argument of type 9999 is not assignable to parameter of type string" width="808" height="203" loading="lazy"></p> <p>That's because when we defined our alert store in the <code>stores.ts</code> file with:</p> <div class="code-example"><div class="example-header"><span class="language-name">js</span></div><pre class="brush: js notranslate"><code>export const alert = writable("Welcome to the To-Do list app!"); </code></pre></div> <p>TypeScript inferred the generic type to be <code>string</code>. If we wanted to be explicit about it, we could do the following:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>export const alert = writable<string>("Welcome to the To-Do list app!"); </code></pre></div> <p>Now we'll make our <code>localStore</code> store support generics. Remember that we defined the <code>JsonValue</code> type to prevent the usage of our <code>localStore</code> store with values that cannot be persisted using <code>JSON.stringify()</code>. Now we want the consumers of <code>localStore</code> to be able to specify the type of data to persist, but instead of working with any type, they should comply with the <code>JsonValue</code> type. We'll specify that with a Generic constraint, like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>export const localStore = <T extends JsonValue>(key: string, initial: T) </code></pre></div> <p>We define a generic type <code>T</code> and specify that it must be compatible with the <code>JsonValue</code> type. Then we'll use the <code>T</code> type appropriately.</p> <p>Our <code>localStore.ts</code> file will end up like this — try the new code now in your version:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>// localStore.ts import { writable } from "svelte/store"; import type { JsonValue } from "./types/json.type"; export const localStore = <T extends JsonValue>(key: string, initial: T) => { // receives the key of the local storage and an initial value const toString = (value: T) => JSON.stringify(value, null, 2); // helper function const toObj = JSON.parse; // helper function if (localStorage.getItem(key) === null) { // item not present in local storage localStorage.setItem(key, toString(initial)); // initialize local storage with initial value } const saved = toObj(localStorage.getItem(key)); // convert to object const { subscribe, set, update } = writable<T>(saved); // create the underlying writable store return { subscribe, set: (value: T) => { localStorage.setItem(key, toString(value)); // save also to local storage as a string return set(value); }, update, }; }; </code></pre></div> <p>And thanks to generic type inference, TypeScript already knows that our <code>$todos</code> store should contain an array of <code>TodoType</code>:</p> <p><img src="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/14-vscode-generic-localstore-error.png" alt="Todo Type object property complete should be completed" width="1415" height="147" loading="lazy"></p> <p>Once again, if we wanted to be explicit about it, we could do so in the <code>stores.ts</code> file like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">ts</span></div><pre class="brush: ts notranslate"><code>const initialTodos: TodoType[] = [ { id: 1, name: "Visit MDN web docs", completed: true }, { id: 2, name: "Complete the Svelte Tutorial", completed: false }, ]; export const todos = localStore<TodoType[]>("mdn-svelte-todo", initialTodos); </code></pre></div> <p>That will do for our brief tour of TypeScript Generics.</p></div></section><section aria-labelledby="the_code_so_far"><h2 id="the_code_so_far"><a href="#the_code_so_far">The code so far</a></h2><div class="section-content"></div></section><section aria-labelledby="git_2"><h3 id="git_2"><a href="#git_2">Git</a></h3><div class="section-content"><p>To see the state of the code as it should be at the end of this article, access your copy of our repo like this:</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>cd mdn-svelte-tutorial/08-next-steps </code></pre></div> <p>Or directly download the folder's content:</p> <div class="code-example"><div class="example-header"><span class="language-name">bash</span></div><pre class="brush: bash notranslate"><code>npx degit opensas/mdn-svelte-tutorial/08-next-steps </code></pre></div> <p>Remember to run <code>npm install && npm run dev</code> to start your app in development mode.</p></div></section><section aria-labelledby="repl_2"><h3 id="repl_2"><a href="#repl_2">REPL</a></h3><div class="section-content"><p>As we said earlier, TypeScript is not yet available in the REPL.</p></div></section><section aria-labelledby="summary"><h2 id="summary"><a href="#summary">Summary</a></h2><div class="section-content"><p>In this article we took our to-do list application and ported it to TypeScript.</p> <p>We first learnt about TypeScript and what advantages it can bring us. Then we saw how to create a new Svelte project with TypeScript support. We also saw how to convert an existing Svelte project to use TypeScript — our to-do list app.</p> <p>We saw how to work with <a href="https://code.visualstudio.com/" class="external" target="_blank">Visual Studio Code</a> and the <a href="https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode" class="external" target="_blank">Svelte extension</a> to get features like type checking and auto-completion. We also used the <code>svelte-check</code> tool to inspect TypeScript issues from the command line.</p> <p>In the next article we will learn how to compile and deploy our app to production. We will also see which resources are available online to go further with learning Svelte.</p> <ul class="prev-next"><li><a class="button secondary" href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_stores"><span class="button-wrap"> Previous </span></a></li><li><a class="button secondary" href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries"><span class="button-wrap"> Overview: JavaScript frameworks and libraries</span></a></li><li><a class="button secondary" href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_deployment_next"><span class="button-wrap"> Next </span></a></li></ul></div></section></article><aside class="article-footer"><div class="article-footer-inner"><div class="svg-container"><svg xmlns="http://www.w3.org/2000/svg" width="162" height="162" viewBox="0 0 162 162" fill="none" role="none"><mask id="b" fill="#fff"><path d="M97.203 47.04c8.113-7.886 18.004-13.871 28.906-17.492a78 78 0 0 1 33.969-3.39c11.443 1.39 22.401 5.295 32.024 11.411s17.656 14.28 23.476 23.86c5.819 9.579 9.269 20.318 10.083 31.385a69.85 69.85 0 0 1-5.387 32.44c-4.358 10.272-11.115 19.443-19.747 26.801-8.632 7.359-18.908 12.709-30.034 15.637l-6.17-21.698c7.666-2.017 14.746-5.703 20.694-10.773 5.948-5.071 10.603-11.389 13.606-18.467a48.14 48.14 0 0 0 3.712-22.352c-.561-7.625-2.938-15.025-6.948-21.625s-9.544-12.226-16.175-16.44-14.181-6.904-22.065-7.863a53.75 53.75 0 0 0-23.405 2.336c-7.513 2.495-14.327 6.62-19.918 12.053z"></path></mask><path stroke="url(#a)" stroke-dasharray="6, 6" stroke-width="2" d="M97.203 47.04c8.113-7.886 18.004-13.871 28.906-17.492a78 78 0 0 1 33.969-3.39c11.443 1.39 22.401 5.295 32.024 11.411s17.656 14.28 23.476 23.86c5.819 9.579 9.269 20.318 10.083 31.385a69.85 69.85 0 0 1-5.387 32.44c-4.358 10.272-11.115 19.443-19.747 26.801-8.632 7.359-18.908 12.709-30.034 15.637l-6.17-21.698c7.666-2.017 14.746-5.703 20.694-10.773 5.948-5.071 10.603-11.389 13.606-18.467a48.14 48.14 0 0 0 3.712-22.352c-.561-7.625-2.938-15.025-6.948-21.625s-9.544-12.226-16.175-16.44-14.181-6.904-22.065-7.863a53.75 53.75 0 0 0-23.405 2.336c-7.513 2.495-14.327 6.62-19.918 12.053z" mask="url(#b)" style="stroke:url(#a)" transform="translate(-63.992 -25.587)"></path><ellipse cx="8.066" cy="111.597" fill="var(--background-tertiary)" rx="53.677" ry="53.699" transform="matrix(.71707 -.697 .7243 .6895 0 0)"></ellipse><g clip-path="url(#c)" transform="translate(-63.992 -25.587)"><path fill="#9abff5" d="m144.256 137.379 32.906 12.434a4.41 4.41 0 0 1 2.559 5.667l-9.326 24.679a4.41 4.41 0 0 1-5.667 2.559l-8.226-3.108-2.332 6.17c-.466 1.233-.375 1.883-1.609 1.417l-2.253-.527c-.411-.155-.95-.594-1.206-1.161l-4.734-10.484-12.545-4.741a4.41 4.41 0 0 1-2.559-5.667l9.325-24.679a4.41 4.41 0 0 1 5.667-2.559m9.961 29.617 8.227 3.108 3.264-8.638-.498-6.768-4.113-1.555.548 7.258-4.319-1.632zm-12.339-4.663 8.226 3.108 3.264-8.637-.498-6.769-4.113-1.554.548 7.257-4.319-1.632z"></path></g><g clip-path="url(#d)" transform="translate(-63.992 -25.587)"><path fill="#81b0f3" d="M135.35 60.136 86.67 41.654c-3.346-1.27-7.124.428-8.394 3.775L64.414 81.938c-1.27 3.347.428 7.125 3.774 8.395l12.17 4.62-3.465 9.128c-.693 1.826-1.432 2.457.394 3.15l3.014 1.625c.609.231 1.637.274 2.477-.104l15.53-6.983 18.56 7.047c3.346 1.27 7.124-.428 8.395-3.775l13.862-36.51c1.27-3.346-.428-7.124-3.775-8.395M95.261 83.207l-12.17-4.62 4.852-12.779 7.19-7.017 6.085 2.31-7.725 7.51 6.389 2.426zm18.255 6.93-12.17-4.62 4.852-12.778 7.189-7.017 6.085 2.31-7.725 7.51 6.39 2.426z"></path></g><defs><clipPath id="c"><path fill="#fff" d="m198.638 146.586-65.056-24.583-24.583 65.057 65.056 24.582z"></path></clipPath><clipPath id="d"><path fill="#fff" d="m66.438 14.055 96.242 36.54-36.54 96.243-96.243-36.54z"></path></clipPath><linearGradient id="a" x1="97.203" x2="199.995" y1="47.04" y2="152.793" gradientUnits="userSpaceOnUse"><stop stop-color="#086DFC"></stop><stop offset="0.246" stop-color="#2C81FA"></stop><stop offset="0.516" stop-color="#5497F8"></stop><stop offset="0.821" stop-color="#80B0F6"></stop><stop offset="1" stop-color="#9ABFF5"></stop></linearGradient></defs></svg></div><h2>Help improve MDN</h2><fieldset class="feedback"><label>Was this page helpful to you?</label><div class="button-container"><button type="button" class="button primary has-icon yes"><span class="button-wrap"><span class="icon icon-thumbs-up "></span>Yes</span></button><button type="button" class="button primary has-icon no"><span class="button-wrap"><span class="icon icon-thumbs-down "></span>No</span></button></div></fieldset><a class="contribute" href="https://github.com/mdn/content/blob/main/CONTRIBUTING.md" title="This will take you to our contribution guidelines on GitHub." target="_blank" rel="noopener noreferrer">Learn how to contribute</a>.<p class="last-modified-date">This page was last modified on<!-- --> <time dateTime="2024-12-19T15:37:45.000Z">Dec 19, 2024</time> by<!-- --> <a href="/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/contributors.txt" rel="nofollow">MDN contributors</a>.</p><div id="on-github" class="on-github"><a href="https://github.com/mdn/content/blob/main/files/en-us/learn_web_development/core/frameworks_libraries/svelte_typescript/index.md?plain=1" title="Folder: en-us/learn_web_development/core/frameworks_libraries/svelte_typescript (Opens in a new tab)" target="_blank" rel="noopener noreferrer">View this page on GitHub</a> <!-- -->•<!-- --> <a href="https://github.com/mdn/content/issues/new?template=page-report.yml&mdn-url=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FLearn_web_development%2FCore%2FFrameworks_libraries%2FSvelte_TypeScript&metadata=%3C%21--+Do+not+make+changes+below+this+line+--%3E%0A%3Cdetails%3E%0A%3Csummary%3EPage+report+details%3C%2Fsummary%3E%0A%0A*+Folder%3A+%60en-us%2Flearn_web_development%2Fcore%2Fframeworks_libraries%2Fsvelte_typescript%60%0A*+MDN+URL%3A+https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FLearn_web_development%2FCore%2FFrameworks_libraries%2FSvelte_TypeScript%0A*+GitHub+URL%3A+https%3A%2F%2Fgithub.com%2Fmdn%2Fcontent%2Fblob%2Fmain%2Ffiles%2Fen-us%2Flearn_web_development%2Fcore%2Fframeworks_libraries%2Fsvelte_typescript%2Findex.md%0A*+Last+commit%3A+https%3A%2F%2Fgithub.com%2Fmdn%2Fcontent%2Fcommit%2F5b20f5f4265f988f80f513db0e4b35c7e0cd70dc%0A*+Document+last+modified%3A+2024-12-19T15%3A37%3A45.000Z%0A%0A%3C%2Fdetails%3E" title="This will take you to GitHub to file a new issue." target="_blank" rel="noopener noreferrer">Report a problem with this content</a></div></div></aside></main></div></div><footer id="nav-footer" class="page-footer"><div class="page-footer-grid"><div class="page-footer-logo-col"><a href="/" class="mdn-footer-logo" aria-label="MDN homepage"><svg width="48" height="17" viewBox="0 0 48 17" fill="none" xmlns="http://www.w3.org/2000/svg"><title id="mdn-footer-logo-svg">MDN logo</title><path d="M20.04 16.512H15.504V10.416C15.504 9.488 15.344 8.824 15.024 8.424C14.72 8.024 14.264 7.824 13.656 7.824C12.92 7.824 12.384 8.064 12.048 8.544C11.728 9.024 11.568 9.64 11.568 10.392V14.184H13.008V16.512H8.472V10.416C8.472 9.488 8.312 8.824 7.992 8.424C7.688 8.024 7.232 7.824 6.624 7.824C5.872 7.824 5.336 8.064 5.016 8.544C4.696 9.024 4.536 9.64 4.536 10.392V14.184H6.6V16.512H0V14.184H1.44V8.04H0.024V5.688H4.536V7.32C5.224 6.088 6.32 5.472 7.824 5.472C8.608 5.472 9.328 5.664 9.984 6.048C10.64 6.432 11.096 7.016 11.352 7.8C11.992 6.248 13.168 5.472 14.88 5.472C15.856 5.472 16.72 5.776 17.472 6.384C18.224 6.992 18.6 7.936 18.6 9.216V14.184H20.04V16.512Z" fill="currentColor"></path><path d="M33.6714 16.512H29.1354V14.496C28.8314 15.12 28.3834 15.656 27.7914 16.104C27.1994 16.536 26.4154 16.752 25.4394 16.752C24.0154 16.752 22.8954 16.264 22.0794 15.288C21.2634 14.312 20.8554 12.984 20.8554 11.304C20.8554 9.688 21.2554 8.312 22.0554 7.176C22.8554 6.04 24.0634 5.472 25.6794 5.472C26.5594 5.472 27.2794 5.648 27.8394 6C28.3994 6.352 28.8314 6.8 29.1354 7.344V2.352H26.9754V0H32.2314V14.184H33.6714V16.512ZM29.1354 11.04V10.776C29.1354 9.88 28.8954 9.184 28.4154 8.688C27.9514 8.176 27.3674 7.92 26.6634 7.92C25.9754 7.92 25.3674 8.176 24.8394 8.688C24.3274 9.2 24.0714 10.008 24.0714 11.112C24.0714 12.152 24.3114 12.944 24.7914 13.488C25.2714 14.032 25.8394 14.304 26.4954 14.304C27.3114 14.304 27.9514 13.96 28.4154 13.272C28.8954 12.584 29.1354 11.84 29.1354 11.04Z" fill="currentColor"></path><path d="M47.9589 16.512H41.9829V14.184H43.4229V10.416C43.4229 9.488 43.2629 8.824 42.9429 8.424C42.6389 8.024 42.1829 7.824 41.5749 7.824C40.8389 7.824 40.2709 8.056 39.8709 8.52C39.4709 8.968 39.2629 9.56 39.2469 10.296V14.184H40.6869V16.512H34.7109V14.184H36.1509V8.04H34.5909V5.688H39.2469V7.344C39.9669 6.096 41.1269 5.472 42.7269 5.472C43.7509 5.472 44.6389 5.776 45.3909 6.384C46.1429 6.992 46.5189 7.936 46.5189 9.216V14.184H47.9589V16.512Z" fill="currentColor"></path></svg></a><p>Your blueprint for a better internet.</p><ul class="social-icons"><li><a href="https://mastodon.social/@mdn" target="_blank" rel="me noopener noreferrer"><span class="icon icon-mastodon"></span><span class="visually-hidden">MDN on Mastodon</span></a></li><li><a href="https://twitter.com/mozdevnet" target="_blank" rel="noopener noreferrer"><span class="icon icon-twitter-x"></span><span class="visually-hidden">MDN on X (formerly Twitter)</span></a></li><li><a href="https://github.com/mdn/" target="_blank" rel="noopener noreferrer"><span class="icon icon-github-mark-small"></span><span class="visually-hidden">MDN on GitHub</span></a></li><li><a href="/en-US/blog/rss.xml" target="_blank"><span class="icon icon-feed"></span><span class="visually-hidden">MDN Blog RSS Feed</span></a></li></ul></div><div class="page-footer-nav-col-1"><h2 class="footer-nav-heading">MDN</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a href="/en-US/about">About</a></li><li class="footer-nav-item"><a href="/en-US/blog/">Blog</a></li><li class="footer-nav-item"><a href="https://www.mozilla.org/en-US/careers/listings/?team=ProdOps" target="_blank" rel="noopener noreferrer">Careers</a></li><li class="footer-nav-item"><a href="/en-US/advertising">Advertise with us</a></li></ul></div><div class="page-footer-nav-col-2"><h2 class="footer-nav-heading">Support</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a class="footer-nav-link" href="https://support.mozilla.org/products/mdn-plus">Product help</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/docs/MDN/Community/Issues">Report an issue</a></li></ul></div><div class="page-footer-nav-col-3"><h2 class="footer-nav-heading">Our communities</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/community">MDN Community</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="https://discourse.mozilla.org/c/mdn/236" target="_blank" rel="noopener noreferrer">MDN Forum</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/discord" target="_blank" rel="noopener noreferrer">MDN Chat</a></li></ul></div><div class="page-footer-nav-col-4"><h2 class="footer-nav-heading">Developers</h2><ul class="footer-nav-list"><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/docs/Web">Web Technologies</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/docs/Learn">Learn Web Development</a></li><li class="footer-nav-item"><a class="footer-nav-link" href="/en-US/plus">MDN Plus</a></li><li class="footer-nav-item"><a href="https://hacks.mozilla.org/" target="_blank" rel="noopener noreferrer">Hacks Blog</a></li></ul></div><div class="page-footer-moz"><a href="https://www.mozilla.org/" class="footer-moz-logo-link" target="_blank" rel="noopener noreferrer"><svg xmlns="http://www.w3.org/2000/svg" width="137" height="32" fill="none" viewBox="0 0 267.431 62.607"><path fill="currentColor" d="m13.913 23.056 5.33 25.356h2.195l5.33-25.356h14.267v38.976h-7.578V29.694h-2.194l-7.264 32.337h-7.343L9.418 29.694H7.223v32.337H-.354V23.056Zm47.137 9.123c9.12 0 14.423 5.385 14.423 15.214s-5.33 15.214-14.423 15.214c-9.12 0-14.423-5.385-14.423-15.214 0-9.855 5.304-15.214 14.423-15.214m0 24.363c4.285 0 6.428-2.196 6.428-7.032v-4.287c0-4.836-2.143-7.032-6.428-7.032s-6.428 2.196-6.428 7.032v4.287c0 4.836 2.143 7.032 6.428 7.032m18.473-.157 15.47-18.01h-15.26v-5.647h24.352v5.646L88.616 56.385h15.704v5.646H79.523Zm29.318-23.657h11.183V62.03h-7.578V38.375h-3.632v-5.646zm3.605-9.672h7.578v5.646h-7.578zm13.17 0h11.21v38.976h-7.578v-33.33h-3.632zm16.801 0H153.6v38.976h-7.577v-33.33h-3.632v-5.646zm29.03 9.123c4.442 0 7.394 2.143 8.231 5.881h2.194v-5.332h9.276v5.646h-3.632v18.011h3.632v5.646h-4.442c-3.135 0-4.834-1.699-4.834-4.836V56.7h-2.194c-.81 3.738-3.789 5.881-8.23 5.881-6.978 0-11.916-5.829-11.916-15.214 0-9.384 4.938-15.187 11.915-15.187m2.3 24.363c4.284 0 6.192-2.196 6.192-7.032v-4.287c0-4.836-1.908-7.032-6.193-7.032-4.18 0-6.193 2.196-6.193 7.032v4.287c0 4.836 2.012 7.032 6.193 7.032m48.34 5.489h-7.577V0h7.577zm6.585-29.643h32.165v-2.196l-21.295-7.634v-6.143l21.295-7.633V6.588h-25.345V0h32.165v12.522l-17.35 5.881V20.6l17.35 5.882v12.521h-38.985zm0-25.801h6.794v6.796h-6.794z"></path></svg></a><ul class="footer-moz-list"><li class="footer-moz-item"><a href="https://www.mozilla.org/privacy/websites/" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Website Privacy Notice</a></li><li class="footer-moz-item"><a href="https://www.mozilla.org/privacy/websites/#cookies" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Cookies</a></li><li class="footer-moz-item"><a href="https://www.mozilla.org/about/legal/terms/mozilla" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Legal</a></li><li class="footer-moz-item"><a href="https://www.mozilla.org/about/governance/policies/participation/" class="footer-moz-link" target="_blank" rel="noopener noreferrer">Community Participation Guidelines</a></li></ul></div><div class="page-footer-legal"><p id="license" class="page-footer-legal-text">Visit<!-- --> <a href="https://www.mozilla.org" target="_blank" rel="noopener noreferrer">Mozilla Corporation’s</a> <!-- -->not-for-profit parent, the<!-- --> <a target="_blank" rel="noopener noreferrer" href="https://foundation.mozilla.org/">Mozilla Foundation</a>.<br/>Portions of this content are ©1998–<!-- -->2025<!-- --> by individual mozilla.org contributors. Content available under<!-- --> <a href="/en-US/docs/MDN/Writing_guidelines/Attrib_copyright_license">a Creative Commons license</a>.</p></div></div></footer></div><script type="application/json" id="hydration">{"url":"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript","doc":{"body":[{"type":"prose","value":{"id":null,"title":null,"isH3":false,"content":"<ul class=\"prev-next\"><li><a class=\"button secondary\" href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_stores\"><span class=\"button-wrap\"> Previous </span></a></li><li><a class=\"button secondary\" href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries\"><span class=\"button-wrap\"> Overview: JavaScript frameworks and libraries</span></a></li><li><a class=\"button secondary\" href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_deployment_next\"><span class=\"button-wrap\"> Next </span></a></li></ul>\n<p>In the last article we learned about Svelte stores and even implemented our own custom store to persist the app's information to Web Storage. We also had a look at using the transition directive to implement animations on DOM elements in Svelte.</p>\n<p>We will now learn how to use TypeScript in Svelte applications. First we'll learn what TypeScript is and what benefits it can bring us. Then we'll see how to configure our project to work with TypeScript files. Finally we will go over our app and see what modifications we have to make to fully take advantage of TypeScript features.</p>\n<figure class=\"table-container\"><table>\n <tbody>\n <tr>\n <th scope=\"row\">Prerequisites:</th>\n <td>\n <p>\n At minimum, it is recommended that you are familiar with the core\n <a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content\">HTML</a>,\n <a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics\">CSS</a>, and\n <a href=\"/en-US/docs/Learn_web_development/Core/Scripting\">JavaScript</a> languages, and\n have knowledge of the\n <a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Command_line\">terminal/command line</a>.\n </p>\n <p>\n You'll need a terminal with node and npm installed to compile and build\n your app.\n </p>\n </td>\n </tr>\n <tr>\n <th scope=\"row\">Objective:</th>\n <td>\n Learn how to configure and use TypeScript when developing Svelte\n applications.\n </td>\n </tr>\n </tbody>\n</table></figure>\n<p>Note that our application is fully functional, and porting it to TypeScript is completely optional. There are different opinions about it, and in this chapter we will talk briefly about the pros and cons of using TypeScript. Even if you are not planning to adopt it, this article will be useful for allowing you to learn what it has to offer and help you make your own decision. If you are not interested at all in TypeScript, you can skip to the next chapter, where we will look at different options for deploying our Svelte applications, further resources, and more.</p>"}},{"type":"prose","value":{"id":"code_along_with_us","title":"Code along with us","isH3":false,"content":""}},{"type":"prose","value":{"id":"git","title":"Git","isH3":true,"content":"<p>Clone the GitHub repo (if you haven't already done it) with:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>git clone https://github.com/opensas/mdn-svelte-tutorial.git\n</code></pre></div>\n<p>Then to get to the current app state, run</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>cd mdn-svelte-tutorial/07-typescript-support\n</code></pre></div>\n<p>Or directly download the folder's content:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>npx degit opensas/mdn-svelte-tutorial/07-typescript-support\n</code></pre></div>\n<p>Remember to run <code>npm install && npm run dev</code> to start your app in development mode.</p>"}},{"type":"prose","value":{"id":"repl","title":"REPL","isH3":true,"content":"<p>Unfortunately, <a href=\"https://github.com/sveltejs/sites/issues/156\" class=\"external\" target=\"_blank\">TypeScript support is not yet available in the REPL</a>.</p>"}},{"type":"prose","value":{"id":"typescript_optional_static_typing_for_javascript","title":"TypeScript: optional static typing for JavaScript","isH3":false,"content":"<p><a href=\"https://www.typescriptlang.org/\" class=\"external\" target=\"_blank\">TypeScript</a> is a superset of JavaScript that provides features such as optional static typing, classes, interfaces, and generics. The goal of TypeScript is to help catch mistakes early through its type system and make JavaScript development more efficient. One of the big benefits is enabling IDEs to provide a richer environment for spotting common errors as you type the code.</p>\n<p>Best of all, JavaScript code is valid TypeScript code; TypeScript is a superset of JavaScript. You can rename most of your <code>.js</code> files to <code>.ts</code> files and they will just work.</p>\n<p>Our TypeScript code will be able to run everywhere JavaScript can run. How is that possible? TypeScript \"transpiles\" our code to vanilla JavaScript. That means that it parses TypeScript code and produces the equivalent vanilla JavaScript code for browsers to run.</p>\n<div class=\"notecard note\">\n<p><strong>Note:</strong>\nIf you are curious about how TypeScript transpiles our code to JavaScript, you can have a look at the <a href=\"https://www.typescriptlang.org/play/?target=1&e=4#example/hello-world\" class=\"external\" target=\"_blank\">TypeScript Playground</a>.</p>\n</div>\n<p>First-class TypeScript support has been Svelte's most requested feature for quite some time. Thanks to the hard work of the Svelte team, together with many contributors, they have an <a href=\"https://svelte.dev/blog/svelte-and-typescript\" class=\"external\" target=\"_blank\">official solution</a> ready to be put to the test. In this section we'll show you how to set up a Svelte project with TypeScript support to give it a try.</p>"}},{"type":"prose","value":{"id":"why_typescript","title":"Why TypeScript?","isH3":false,"content":"<p>TypeScript's main advantages are:</p>\n<ul>\n<li>Early spotted bugs: The compiler checks types at compile time and provides error reporting.</li>\n<li>Readability: Static typing gives the code more structure, making it self-documenting and more readable.</li>\n<li>Rich IDE support: Type information allows code editors and IDEs to offer features like code navigation, autocompletion, and smarter hints.</li>\n<li>Safer refactoring: Types allows IDEs to know more about your code, and assist you while refactoring large portions of your code base.</li>\n<li>Type inference: Enables you to take advantage of many TypeScript features even without declaring variable types.</li>\n<li>Availability of new and future JavaScript features: TypeScript transpiles many recent JavaScript features to plain old-school JavaScript, allowing you to use them even on user-agents that don't support them natively yet.</li>\n</ul>\n<p>TypeScript also has some disadvantages:</p>\n<ul>\n<li>Not true static typing: Types are only checked at compile time, and they are removed from the generated code.</li>\n<li>Steep learning curve: Even though TypeScript is a superset of JavaScript and not a completely new language, there is a considerable learning curve, especially if you have no experience at all with static languages like Java or C#.</li>\n<li>More code: You have to write and maintain more code.</li>\n<li>No replacement for automatic tests: Even though types might help you catch several bugs, TypeScript is not a true replacement for a comprehensive suite of automated tests.</li>\n<li>Boilerplate code: Working with types, classes, interfaces, and generics can lead to over-engineered code bases.</li>\n</ul>\n<p>There seems to be a broad consensus that TypeScript is particularly well suited for large-scale projects, with many developers working on the same codebase. And it is indeed being used by several large-scale projects, like Angular 2, Vue 3, Ionic, Visual Studio Code, Jest, and even the Svelte compiler. Nevertheless, some developers prefer to use it even on small projects like the one we are developing.</p>\n<p>In the end, it's your decision. In the following sections we hope to give you more evidence to make up your mind about it.</p>"}},{"type":"prose","value":{"id":"creating_a_svelte_typescript_project_from_scratch","title":"Creating a Svelte TypeScript project from scratch","isH3":false,"content":"<p>You can start a new Svelte TypeScript project using the <a href=\"https://github.com/sveltejs/template\" class=\"external\" target=\"_blank\">standard template</a>. All you have to do is run the following terminal commands (run them somewhere where you are storing your Svelte test projects — it creates a new directory):</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>npx degit sveltejs/template svelte-typescript-app\n\ncd svelte-typescript-app\n\nnode scripts/setupTypeScript.js\n</code></pre></div>\n<p>This creates a starter project that includes TypeScript support, which you can then modify as you wish.</p>\n<p>Then you'll have to tell npm to download dependencies and start the project in development mode, as we usually do:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>npm install\n\nnpm run dev\n</code></pre></div>"}},{"type":"prose","value":{"id":"adding_typescript_support_to_an_existing_svelte_project","title":"Adding TypeScript support to an existing Svelte Project","isH3":false,"content":"<p>To add TypeScript support to an existing Svelte project, you can <a href=\"https://svelte.dev/blog/svelte-and-typescript#Adding_TypeScript_to_an_existing_project\" class=\"external\" target=\"_blank\">follow these instructions</a>. Alternatively, you can download the <a href=\"https://github.com/sveltejs/template/blob/master/scripts/setupTypeScript.js\" class=\"external\" target=\"_blank\"><code>setupTypeScript.js</code></a> file to a <code>scripts</code> folder inside your project's root folder, and then run <code>node scripts/setupTypeScript.js</code>.</p>\n<p>You can even use <code>degit</code> to download the script. That's what we will do to start porting our application to TypeScript.</p>\n<div class=\"notecard note\">\n<p><strong>Note:</strong>\nRemember that you can run <code>npx degit opensas/mdn-svelte-tutorial/07-typescript-support svelte-todo-typescript</code> to get the complete to-do list application in JavaScript before you start porting it to TypeScript.</p>\n</div>\n<p>Go to the root directory of the project and enter these commands:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>npx degit sveltejs/template/scripts scripts # download script file to a scripts folder\n\nnode scripts/setupTypeScript.js # run it\n# Converted to TypeScript.\n</code></pre></div>\n<p>You will need to re-run your dependency manager to get started.</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>npm install # download new dependencies\n\nnpm run dev # start the app in development mode\n</code></pre></div>\n<p>These instructions apply to any Svelte project you'd like to convert to TypeScript. Just take into account that the Svelte community is constantly improving Svelte TypeScript support, so you should run <code>npm update</code> regularly to take advantage of the latest changes.</p>\n<div class=\"notecard note\">\n<p><strong>Note:</strong>\nIf you find any trouble working with TypeScript inside a Svelte application, have a look at this <a href=\"https://github.com/sveltejs/language-tools/blob/master/docs/preprocessors/typescript.md#troubleshooting--faq\" class=\"external\" target=\"_blank\">troubleshooting/FAQ section about TypeScript support</a>.</p>\n</div>\n<p>As we said before, TypeScript is a superset of JavaScript, so your application will run without modifications. Currently you will be running a regular JavaScript application with TypeScript support enabled, without taking advantage of any of the features that TypeScript provides. You can now start adding types progressively.</p>\n<p>Once you have TypeScript configured, you can start using it from a Svelte component by just adding a <code><script lang='ts'></code> at the beginning of the script section. To use it from regular JavaScript files, just change the file extension from <code>.js</code> to <code>.ts</code>. You'll also have to update any corresponding import statements to remove the <code>.ts</code> file extension from all <code>import</code> statements.</p>\n<div class=\"notecard note\">\n<p><strong>Note:</strong>\nTypeScript will throw an error if you use the <code>.ts</code> file extension in an <code>import</code> statement, so you if you have a file <code>./foo.ts</code>, you must import it as \"./foo\".\nSee the <a href=\"https://www.typescriptlang.org/docs/handbook/modules/theory.html#module-resolution-for-bundlers-typescript-runtimes-and-nodejs-loaders\" class=\"external\" target=\"_blank\">Module resolution for bundlers, TypeScript runtimes, and Node.js loaders</a> section of the TypeScript manual for more information.</p>\n</div>\n<div class=\"notecard note\">\n<p><strong>Note:</strong>\nUsing TypeScript in component markup sections is not supported in Svelte 4, which this guide is based on.\nSo while you can use JavaScript from the markup, you'll have to use TypeScript in the <code><script lang='ts'></code> section.\nTypeScript in component markup is allowed from Svelte 5.</p>\n</div>"}},{"type":"prose","value":{"id":"improved_developer_experience_with_typescript","title":"Improved developer experience with TypeScript","isH3":false,"content":"<p>TypeScript provides code editors and IDEs with lots of information to allow them to deliver a friendlier development experience.</p>\n<p>We'll use <a href=\"https://code.visualstudio.com/\" class=\"external\" target=\"_blank\">Visual Studio Code</a> to do a quick test and see how we can get autocompletion hints and type-checking as we're writing components.</p>\n<div class=\"notecard note\">\n<p><strong>Note:</strong>\nIf you don't wish to use VS Code, we also provide instructions for using TypeScript error checking from the terminal instead, slightly later on.</p>\n</div>\n<p>There is work in progress to support TypeScript in Svelte projects in several code editors; the most complete support so far is available in the <a href=\"https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode\" class=\"external\" target=\"_blank\">Svelte for VS Code extension</a>, which is developed and maintained by the Svelte team. This extension offers type checking, inspecting, refactoring, intellisense, hover-information, auto-completion, and other features. This kind of developer assistance is another good reason to start using TypeScript in your projects.</p>\n<div class=\"notecard note\">\n<p><strong>Note:</strong>\nMake sure you are using <a href=\"https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode\" class=\"external\" target=\"_blank\">Svelte for VS Code</a> and NOT the old \"Svelte\" by James Birtles, which has been discontinued. In case you have it installed, you should uninstall it and install the official Svelte extension instead.</p>\n</div>\n<p>Assuming you are inside the VS Code application, from the root of your project's folder, type <code>code .</code> (the trailing dot tells VS Code to open the current folder) to open the code editor. VS Code will tell you that there are recommended extensions to install.</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/01-vscode-extension-recommendations.png\" alt=\"Dialog box saying this workspace has extension recommendations, with options to install or show a list\" width=\"475\" height=\"108\" loading=\"lazy\"></p>\n<p>Clicking <em>Install all</em> will install Svelte for VS Code.</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/02-svelte-for-vscode.png\" alt=\"Svelte for VS Code extension information\" width=\"1043\" height=\"210\" loading=\"lazy\"></p>\n<p>We can also see that the <code>setupTypeScript.js</code> file made a couple of changes to our project. The <code>main.js</code> file has been renamed to <code>main.ts</code>, which means that VS Code can provide hover-information on our Svelte components:</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/03-vscode-hints-in-main-ts.png\" alt=\"VS Code screenshot showing that when hovering on a component, it gives you hints\" width=\"480\" height=\"287\" loading=\"lazy\"></p>\n\u003c!-- cSpell:ignore traget -->\n<p>We also get type checking for free. If we pass an unknown property in the options parameter of the <code>App</code> constructor (for example a typo like <code>traget</code> instead of <code>target</code>), TypeScript will complain:</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/04-vscode-type-checking-in-main-ts.png\" alt=\"Type checking in VS Code - App object has been given an unknown property traget\" width=\"895\" height=\"277\" loading=\"lazy\"></p>\n<p>In the <code>App.svelte</code> component, the <code>setupTypeScript.js</code> script has added the <code>lang=\"ts\"</code> attribute to the <code><script></code> tag. Moreover, thanks to type inference, in many cases we won't even need to specify types to get code assistance. For example, if you start adding an <code>ms</code> property to the <code>Alert</code> component call, TypeScript will infer from the default value that the <code>ms</code> property should be a number:</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/05-vscode-type-inference-and-code-assistance.png\" alt=\"VS Code type inference and code hinting - ms variable should be a number\" width=\"842\" height=\"387\" loading=\"lazy\"></p>\n<p>And if you pass something that is not a number, it will complain about it:</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/06-vscode-type-checking-in-components.png\" alt=\"Type checking in VS Code - the ms variable has been given a non-numeric value\" width=\"678\" height=\"236\" loading=\"lazy\"></p>\n<p>The application template has a <code>check</code> script configured that runs <code>svelte-check</code> against your code. This package allows you to detect errors and warnings normally displayed by a code editor from the command line, which makes it pretty useful for running it in a continuous integration (CI) pipeline. Just run <code>npm run check</code> to check for unused CSS, and return A11y hints and TypeScript compile errors.</p>\n<p>In this case, if you run <code>npm run check</code> (either in the VS Code console or terminal) you will get the following error:</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/07-vscode-svelte-check.png\" alt=\"Check command being run inside VS Code showing type error, ms variable should be assigned a number\" width=\"753\" height=\"480\" loading=\"lazy\"></p>\n<p>Even better, if you run it from the VS Code integrated terminal (you can open it with the <kbd>Ctrl</kbd> + <kbd>`</kbd> keyboard shortcut), <kbd>Cmd</kbd>/<kbd>Ctrl</kbd> clicking on the file name will take you to the line containing the error.</p>\n<p>You can also run the <code>check</code> script in watch mode with <code>npm run check -- --watch</code>. In this case, the script will execute whenever you change any file. If you are running this in your regular terminal, keep it running in the background in a separate terminal window so that it can keep reporting errors but won't interfere with other terminal usage.</p>"}},{"type":"prose","value":{"id":"creating_a_custom_type","title":"Creating a custom type","isH3":false,"content":"<p>TypeScript supports structural typing. Structural typing is a way of relating types based solely on their members, even if you do not explicitly define the type.</p>\n<p>We'll define a <code>TodoType</code> type to see how TypeScript enforces that anything passed to a component expecting a <code>TodoType</code> will be structurally compatible with it.</p>\n<ol>\n<li>\n<p>Inside the <code>src</code> folder create a <code>types</code> folder.</p>\n</li>\n<li>\n<p>Add a <code>todo.type.ts</code> file inside it.</p>\n</li>\n<li>\n<p>Give <code>todo.type.ts</code> the following content:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>export type TodoType = {\n id: number;\n name: string;\n completed: boolean;\n};\n</code></pre></div>\n<div class=\"notecard note\">\n<p><strong>Note:</strong>\nThe Svelte template uses <a href=\"https://github.com/sveltejs/svelte-preprocess\" class=\"external\" target=\"_blank\">svelte-preprocess</a> 4.0.0 to support TypeScript. From that version onward you have to use <code>export</code>/<code>import</code> type syntax to import types and interfaces. Check <a href=\"https://github.com/sveltejs/language-tools/blob/master/docs/preprocessors/typescript.md#how-do-i-import-interfaces-into-my-svelte-components-i-get-errors-after-transpilation\" class=\"external\" target=\"_blank\">this section of the troubleshooting guide</a> for more information.</p>\n</div>\n</li>\n<li>\n<p>Now we'll use <code>TodoType</code> from our <code>Todo.svelte</code> component. First add the <code>lang=\"ts\"</code> to our <code><script></code> tag.</p>\n</li>\n<li>\n<p>Let's <code>import</code> the type and use it to declare the <code>todo</code> property. Replace the <code>export let todo</code> line with the following:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>import type { TodoType } from \"../types/todo.type\";\n\nexport let todo: TodoType;\n</code></pre></div>\n<p>Note that the <code>.ts</code> file extension is not allowed in the <code>import</code> statement, and has been omitted.</p>\n</li>\n<li>\n<p>Now from <code>Todos.svelte</code> we will instantiate a <code>Todo</code> component with a literal object as its parameter before the call to the <code>MoreActions</code> component, like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">svelte</span></div><pre class=\"brush: svelte notranslate\"><code><hr />\n\n<Todo todo={ { name: 'a new task with no id!', completed: false } } />\n\n<!-- MoreActions -->\n<MoreActions {todos}\n</code></pre></div>\n</li>\n<li>\n<p>Add the <code>lang='ts'</code> to the <code><script></code> tag of the <code>Todos.svelte</code> component so that it knows to use the type checking we have specified.</p>\n<p>We will get the following error:</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/08-vscode-structural-typing.png\" alt=\"Type error in VS Code, Todo Type object requires an id property.\" width=\"996\" height=\"208\" loading=\"lazy\"></p>\n</li>\n</ol>\n<p>By now you should get an idea about the kind of assistance we can get from TypeScript when building Svelte projects.</p>\n<p>Now we will undo these changes in order to start porting our application to TypeScript, so we won't be bothered with all the check warnings.</p>\n<ol>\n<li>Remove the flawed to-do and the <code>lang='ts'</code> attribute from the <code>Todos.svelte</code> file.</li>\n<li>Also remove the import of <code>TodoType</code> and the <code>lang='ts'</code> from <code>Todo.svelte</code>.</li>\n</ol>\n<p>We'll take care of them properly later on.</p>"}},{"type":"prose","value":{"id":"porting_our_to-do_list_app_to_typescript","title":"Porting our to-do list app to TypeScript","isH3":false,"content":"<p>Now we are ready to start porting our to-do list application to take advantage of all the features that TypeScript offers to us.</p>\n<p>Let's start by running the check script in watch mode inside the project root:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>npm run check -- --watch\n</code></pre></div>\n<p>This should output something like the following:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>svelte-check \"--watch\"\n\nLoading svelte-check in workspace: ./svelte-todo-typescript\nGetting Svelte diagnostics...\n====================================\nsvelte-check found no errors and no warnings\n</code></pre></div>\n<p>Note that if you are using a supporting code editor like VS Code, a simple way to start porting a Svelte component is to just add the <code><script lang='ts'></code> at the top of your component and look for the three-dotted hints:</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/09-vscode-alert-hints.png\" alt=\"VS Code screenshot showing that when you add type="ts" to a component, it gives you three dot alert hints\" width=\"903\" height=\"372\" loading=\"lazy\"></p>"}},{"type":"prose","value":{"id":"alert.svelte","title":"Alert.svelte","isH3":true,"content":"<p>Let's start with our <code>Alert.svelte</code> component.</p>\n<ol>\n<li>\n<p>Add <code>lang=\"ts\"</code> into your <code>Alert.svelte</code> component's <code><script></code> tag. You'll see some warnings in the output of the <code>check</code> script:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>npm run check -- --watch\n</code></pre></div>\n<pre class=\"brush: plain notranslate\">> svelte-check \"--watch\"\n\n./svelte-todo-typescript\nGetting Svelte diagnostics...\n====================================\n\n./svelte-todo-typescript/src/components/Alert.svelte:8:7\nWarn: Variable 'visible' implicitly has an 'any' type, but a better type may be inferred from usage. (ts)\n let visible\n\n./svelte-todo-typescript/src/components/Alert.svelte:9:7\nWarn: Variable 'timeout' implicitly has an 'any' type, but a better type may be inferred from usage. (ts)\n let timeout\n\n./svelte-todo-typescript/src/components/Alert.svelte:11:28\nWarn: Parameter 'message' implicitly has an 'any' type, but a better type may be inferred from usage. (ts)\nChange = (message, ms) => {\n\n./svelte-todo-typescript/src/components/Alert.svelte:11:37\nWarn: Parameter 'ms' implicitly has an 'any' type, but a better type may be inferred from usage. (ts)\n(message, ms) => {\n</pre>\n</li>\n<li>\n<p>You can fix these by specifying the corresponding types, like so:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>export let ms = 3000\n\n let visible: boolean\n let timeout: number\n\n const onMessageChange = (message: string, ms: number) => {\n clearTimeout(timeout)\n if (!message) { // hide Alert if message is empty\n</code></pre></div>\n<div class=\"notecard note\">\n<p><strong>Note:</strong>\nThere's no need to specify the <code>ms</code> type with <code>export let ms:number = 3000</code>, because TypeScript is already inferring it from its default value.</p>\n</div>\n</li>\n</ol>"}},{"type":"prose","value":{"id":"moreactions.svelte","title":"MoreActions.svelte","isH3":true,"content":"<p>Now we'll do the same for the <code>MoreActions.svelte</code> component.</p>\n<ol>\n<li>\n<p>Add the <code>lang='ts'</code> attribute, like before. TypeScript will warn us about the <code>todos</code> prop and the <code>t</code> variable in the call to <code>todos.filter((t) =>...)</code>.</p>\n<pre class=\"brush: plain notranslate\">Warn: Variable 'todos' implicitly has an 'any' type, but a better type may be inferred from usage. (ts)\n export let todos\n\nWarn: Parameter 't' implicitly has an 'any' type, but a better type may be inferred from usage. (ts)\n $: completedTodos = todos.filter((t) => t.completed).length\n</pre>\n</li>\n<li>\n<p>We will use the <code>TodoType</code> we already defined to tell TypeScript that <code>todos</code> is a <code>TodoType</code> array. Replace the <code>export let todos</code> line with the following:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>import type { TodoType } from \"../types/todo.type\";\n\nexport let todos: TodoType[];\n</code></pre></div>\n</li>\n</ol>\n<p>Notice that now TypeScript can infer that the <code>t</code> variable in <code>todos.filter((t) => t.completed)</code> is of type <code>TodoType</code>. Nevertheless, if we think it makes our code easier to read, we could specify it like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>$: completedTodos = todos.filter((t: TodoType) => t.completed).length;\n</code></pre></div>\n<p>Most of the time, TypeScript will be able to correctly infer the reactive variable type, but sometimes you might get an \"implicitly has an 'any' type\" error when working with reactive assignments. In those cases you can declare the typed variable in a different statement, like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>let completedTodos: number;\n$: completedTodos = todos.filter((t: TodoType) => t.completed).length;\n</code></pre></div>\n<p>You can't specify the type in the reactive assignment itself. The statement <code>$: completedTodos: number = todos.filter[...]</code> is invalid. For more information, read <a href=\"https://github.com/sveltejs/language-tools/blob/master/docs/preprocessors/typescript.md#how-do-i-type-reactive-assignments--i-get-an-implicitly-has-type-any-error\" class=\"external\" target=\"_blank\">How do I type reactive assignments? / I get an \"implicitly has type 'any' error\"</a>.</p>"}},{"type":"prose","value":{"id":"filterbutton.svelte","title":"FilterButton.svelte","isH3":true,"content":"<p>Now we'll take care of the <code>FilterButton</code> component.</p>\n<ol>\n<li>\n<p>Add the <code>lang='ts'</code> attribute to the <code><script></code> tag, as usual. You'll notice there are no warnings — TypeScript infers the type of the filter variable from the default value. But we know that there are only three valid values for the filter: all, active, and completed. So we can let TypeScript know about them by creating an enum Filter.</p>\n</li>\n<li>\n<p>Create a <code>filter.enum.ts</code> file in the <code>types</code> folder.</p>\n</li>\n<li>\n<p>Give it the following contents:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>export enum Filter {\n ALL = \"all\",\n ACTIVE = \"active\",\n COMPLETED = \"completed\",\n}\n</code></pre></div>\n</li>\n<li>\n<p>Now we will use this from the <code>FilterButton</code> component. Replace the content of the <code>FilterButton.svelte</code> file with the following:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">svelte</span></div><pre class=\"brush: svelte notranslate\"><code><!-- components/FilterButton.svelte -->\n<script lang=\"ts\">\n import { Filter } from \"../types/filter.enum\";\n\n export let filter: Filter = Filter.ALL;\n</script>\n\n<div class=\"filters btn-group stack-exception\">\n <button class=\"btn toggle-btn\" class:btn__primary={filter === Filter.ALL} aria-pressed={filter === Filter.ALL} on:click={()=> filter = Filter.ALL} >\n <span class=\"visually-hidden\">Show</span>\n <span>All</span>\n <span class=\"visually-hidden\">tasks</span>\n </button>\n <button class=\"btn toggle-btn\" class:btn__primary={filter === Filter.ACTIVE} aria-pressed={filter === Filter.ACTIVE} on:click={()=> filter = Filter.ACTIVE} >\n <span class=\"visually-hidden\">Show</span>\n <span>Active</span>\n <span class=\"visually-hidden\">tasks</span>\n </button>\n <button class=\"btn toggle-btn\" class:btn__primary={filter === Filter.COMPLETED} aria-pressed={filter === Filter.COMPLETED} on:click={()=> filter = Filter.COMPLETED} >\n <span class=\"visually-hidden\">Show</span>\n <span>Completed</span>\n <span class=\"visually-hidden\">tasks</span>\n </button>\n</div>\n</code></pre></div>\n</li>\n</ol>\n<p>Here we are just importing the <code>Filter</code> enum and using it instead of the string values we used previously.</p>"}},{"type":"prose","value":{"id":"todos.svelte","title":"Todos.svelte","isH3":true,"content":"<p>We will also use the <code>Filter</code> enum in the <code>Todos.svelte</code> component.</p>\n<ol>\n<li>\n<p>First, add the <code>lang='ts'</code> attribute to it, as before.</p>\n</li>\n<li>\n<p>Next, import the <code>Filter</code> enum. Add the following <code>import</code> statement below your existing ones:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>import { Filter } from \"../types/filter.enum\";\n</code></pre></div>\n</li>\n<li>\n<p>Now we will use it whenever we reference the current filter. Replace your two filter-related blocks with the following:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>let filter: Filter = Filter.ALL;\nconst filterTodos = (filter: Filter, todos) =>\n filter === Filter.ACTIVE\n ? todos.filter((t) => !t.completed)\n : filter === Filter.COMPLETED\n ? todos.filter((t) => t.completed)\n : todos;\n\n$: {\n if (filter === Filter.ALL) {\n $alert = \"Browsing all todos\";\n } else if (filter === Filter.ACTIVE) {\n $alert = \"Browsing active todos\";\n } else if (filter === Filter.COMPLETED) {\n $alert = \"Browsing completed todos\";\n }\n}\n</code></pre></div>\n</li>\n<li>\n<p><code>check</code> will still give us some warnings from <code>Todos.svelte</code>. Let's fix them.</p>\n<p>Start by importing the <code>TodoType</code> and telling TypeScript that our <code>todos</code> variable is an array of <code>TodoType</code>. Replace <code>export let todos = []</code> with the following two lines:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>import type { TodoType } from \"../types/todo.type\";\n\nexport let todos: TodoType[] = [];\n</code></pre></div>\n</li>\n<li>\n<p>Next we'll specify all the missing types. The variable <code>todosStatus</code>, which we used to programmatically access the methods exposed by the <code>TodosStatus</code> component, is of type <code>TodosStatus</code>. And each <code>todo</code> will be of type <code>TodoType</code>.</p>\n<p>Update your <code><script></code> section to look like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>import FilterButton from \"./FilterButton.svelte\";\nimport Todo from \"./Todo.svelte\";\nimport MoreActions from \"./MoreActions.svelte\";\nimport NewTodo from \"./NewTodo.svelte\";\nimport TodosStatus from \"./TodosStatus.svelte\";\nimport { alert } from \"../stores\";\n\nimport { Filter } from \"../types/filter.enum\";\n\nimport type { TodoType } from \"../types/todo.type\";\n\nexport let todos: TodoType[] = [];\n\nlet todosStatus: TodosStatus; // reference to TodosStatus instance\n\n$: newTodoId =\n todos.length > 0 ? Math.max(...todos.map((t) => t.id)) + 1 : 1;\n\nfunction addTodo(name: string) {\n todos = [...todos, { id: newTodoId, name, completed: false }];\n $alert = `Todo '${name}' has been added`;\n}\n\nfunction removeTodo(todo: TodoType) {\n todos = todos.filter((t) => t.id !== todo.id);\n todosStatus.focus(); // give focus to status heading\n $alert = `Todo '${todo.name}' has been deleted`;\n}\n\nfunction updateTodo(todo: TodoType) {\n const i = todos.findIndex((t) => t.id === todo.id);\n if (todos[i].name !== todo.name)\n $alert = `todo '${todos[i].name}' has been renamed to '${todo.name}'`;\n if (todos[i].completed !== todo.completed)\n $alert = `todo '${todos[i].name}' marked as ${\n todo.completed ? \"completed\" : \"active\"\n }`;\n todos[i] = { ...todos[i], ...todo };\n}\n\nlet filter: Filter = Filter.ALL;\nconst filterTodos = (filter: Filter, todos: TodoType[]) =>\n filter === Filter.ACTIVE\n ? todos.filter((t) => !t.completed)\n : filter === Filter.COMPLETED\n ? todos.filter((t) => t.completed)\n : todos;\n\n$: {\n if (filter === Filter.ALL) {\n $alert = \"Browsing all todos\";\n } else if (filter === Filter.ACTIVE) {\n $alert = \"Browsing active todos\";\n } else if (filter === Filter.COMPLETED) {\n $alert = \"Browsing completed todos\";\n }\n}\n\nconst checkAllTodos = (completed: boolean) => {\n todos = todos.map((t) => ({ ...t, completed }));\n $alert = `${completed ? \"Checked\" : \"Unchecked\"} ${todos.length} todos`;\n};\nconst removeCompletedTodos = () => {\n $alert = `Removed ${todos.filter((t) => t.completed).length} todos`;\n todos = todos.filter((t) => !t.completed);\n};\n</code></pre></div>\n</li>\n</ol>"}},{"type":"prose","value":{"id":"todosstatus.svelte","title":"TodosStatus.svelte","isH3":true,"content":"<p>We are encountering the following errors related to passing <code>todos</code> to the <code>TodosStatus.svelte</code> (and <code>Todo.svelte</code>) components:</p>\n<pre class=\"brush: plain notranslate\">./src/components/Todos.svelte:70:39\nError: Type 'TodoType[]' is not assignable to type 'undefined'. (ts)\n <TodosStatus bind:this={todosStatus} {todos} />\n\n./src/components/Todos.svelte:76:12\nError: Type 'TodoType' is not assignable to type 'undefined'. (ts)\n <Todo {todo}\n</pre>\n<p>This is because the <code>todos</code> prop in the <code>TodosStatus</code> component has no default value, so TypeScript has inferred it to be of type <code>undefined</code>, which is not compatible with an array of <code>TodoType</code>. The same thing is happening with our Todo component.</p>\n<p>Let's fix it.</p>\n<ol>\n<li>\n<p>Open the file <code>TodosStatus.svelte</code> and add the <code>lang='ts'</code> attribute.</p>\n</li>\n<li>\n<p>Then import the <code>TodoType</code> and declare the <code>todos</code> prop as an array of <code>TodoType</code>. Replace the first line of the <code><script></code> section with the following:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>import type { TodoType } from \"../types/todo.type\";\n\nexport let todos: TodoType[];\n</code></pre></div>\n</li>\n<li>\n<p>We will also specify the <code>headingEl</code>, which we used to bind to the heading tag, as an <code>HTMLElement</code>. Update the <code>let headingEl</code> line with the following:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>let headingEl: HTMLElement;\n</code></pre></div>\n</li>\n<li>\n<p>Finally, you'll notice the following error reported, related to where we set the <code>tabindex</code> attribute. That's because TypeScript is type checking the <code><h2></code> element and expects <code>tabindex</code> to be of type <code>number</code>.</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/10-vscode-tabindex-hint.png\" alt=\"Tabindex hint inside VS Code, tabindex expects a type of number, not string\" width=\"938\" height=\"215\" loading=\"lazy\"></p>\n<p>To fix it, replace <code>tabindex=\"-1\"</code> with <code>tabindex={-1}</code>, like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">svelte</span></div><pre class=\"brush: svelte notranslate\"><code><h2 id=\"list-heading\" bind:this={headingEl} tabindex={-1}>\n {completedTodos} out of {totalTodos} items completed\n</h2>\n</code></pre></div>\n<p>This way TypeScript can prevent us from incorrectly assigning it to a string variable.</p>\n</li>\n</ol>"}},{"type":"prose","value":{"id":"newtodo.svelte","title":"NewTodo.svelte","isH3":true,"content":"<p>Next we will take care of <code>NewTodo.svelte</code>.</p>\n<ol>\n<li>\n<p>As usual, add the <code>lang='ts'</code> attribute.</p>\n</li>\n<li>\n<p>The warning will indicate that we have to specify a type for the <code>nameEl</code> variable. Set its type to <code>HTMLElement</code> like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>let nameEl: HTMLElement; // reference to the name input DOM node\n</code></pre></div>\n</li>\n<li>\n<p>Last for this file, we need to specify the correct type for our <code>autofocus</code> variable. Update its definition like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>export let autofocus: boolean = false;\n</code></pre></div>\n</li>\n</ol>"}},{"type":"prose","value":{"id":"todo.svelte","title":"Todo.svelte","isH3":true,"content":"<p>Now the only warnings that <code>npm run check</code> emits are triggered by calling the <code>Todo.svelte</code> component. Let's fix them.</p>\n<ol>\n<li>\n<p>Open the <code>Todo.svelte</code> file, and add the <code>lang='ts'</code> attribute.</p>\n</li>\n<li>\n<p>Let's import the <code>TodoType</code>, and set the type of the <code>todo</code> prop. Replace the <code>export let todo</code> line with the following:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>import type { TodoType } from \"../types/todo.type\";\n\nexport let todo: TodoType;\n</code></pre></div>\n</li>\n<li>\n<p>The first warning we get is TypeScript telling us to define the type of the <code>update()</code> function's <code>updatedTodo</code> variable. This can be a little tricky because <code>updatedTodo</code> contains only the attributes of the <code>todo</code> that have been updated. That means it's not a complete <code>todo</code> — it only has a subset of a <code>todo</code>'s properties.</p>\n<p>For these kinds of cases, TypeScript provides several <a href=\"https://www.typescriptlang.org/docs/handbook/utility-types.html\" class=\"external\" target=\"_blank\">utility types</a> to make it easier to apply these common transformations. What we need right now is the <a href=\"https://www.typescriptlang.org/docs/handbook/utility-types.html#partialt\" class=\"external\" target=\"_blank\"><code>Partial<T></code></a> utility, which allows us to represent all subsets of a given type. The partial utility returns a new type based on the type <code>T</code>, where every property of <code>T</code> is optional.</p>\n<p>We'll use it in the <code>update()</code> function — update yours like so:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>function update(updatedTodo: Partial<TodoType>) {\n todo = { ...todo, ...updatedTodo }; // applies modifications to todo\n dispatch(\"update\", todo); // emit update event\n}\n</code></pre></div>\n<p>With this we are telling TypeScript that the <code>updatedTodo</code> variable will hold a subset of the <code>TodoType</code> properties.</p>\n</li>\n<li>\n<p>Now svelte-check tells us that we have to define the type of our action function parameters:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>./07-next-steps/src/components/Todo.svelte:45:24\nWarn: Parameter 'node' implicitly has an 'any' type, but a better type may be inferred from usage. (ts)\n const focusOnInit = (node) => node && typeof node.focus === 'function' && node.focus()\n\n./07-next-steps/src/components/Todo.svelte:47:28\nWarn: Parameter 'node' implicitly has an 'any' type, but a better type may be inferred from usage. (ts)\n const focusEditButton = (node) => editButtonPressed && node.focus()\n</code></pre></div>\n<p>We just have to define the node variable to be of type <code>HTMLElement</code>. In the two lines indicated above, replace the first instance of <code>node</code> with <code>node: HTMLElement</code>.</p>\n</li>\n</ol>"}},{"type":"prose","value":{"id":"actions.js","title":"actions.js","isH3":true,"content":"<p>Next we'll take care of the <code>actions.js</code> file.</p>\n<ol>\n<li>\n<p>Rename it to <code>actions.ts</code> and add the type of the node parameter. It should end up looking like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>// actions.ts\nexport function selectOnFocus(node: HTMLInputElement) {\n if (node && typeof node.select === \"function\") {\n // make sure node is defined and has a select() method\n const onFocus = () => node.select(); // event handler\n node.addEventListener(\"focus\", onFocus); // when node gets focus call onFocus()\n return {\n destroy: () => node.removeEventListener(\"focus\", onFocus), // this will be executed when the node is removed from the DOM\n };\n }\n}\n</code></pre></div>\n</li>\n<li>\n<p>Now update <code>Todo.svelte</code> and <code>NewTodo.svelte</code> where we import the actions file. Remember that imports in TypeScript don't include the file extension. In each case it should end up like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>import { selectOnFocus } from \"../actions\";\n</code></pre></div>\n</li>\n</ol>"}},{"type":"prose","value":{"id":"migrating_the_stores_to_typescript","title":"Migrating the stores to TypeScript","isH3":true,"content":"<p>Now we have to migrate the <code>stores.js</code> and <code>localStore.js</code> files to TypeScript.</p>\n<p>Tip: the script <code>npm run check</code>, which uses the <a href=\"https://github.com/sveltejs/language-tools/tree/master/packages/svelte-check\" class=\"external\" target=\"_blank\"><code>svelte-check</code></a> tool, will only check our application's <code>.svelte</code> files. If you want to also check the <code>.ts</code> files, you can run <code>npm run check && npx tsc --noEmit</code>, which tells the TypeScript compiler to check for errors without generating the <code>.js</code> output files. You could even add a script to your <code>package.json</code> file that runs that command.</p>\n<p>We'll start with <code>stores.js</code>.</p>\n<ol>\n<li>\n<p>Rename the file to <code>stores.ts</code>.</p>\n</li>\n<li>\n<p>Set the type of our <code>initialTodos</code> array to <code>TodoType[]</code>. This is how the contents will end up:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>// stores.ts\nimport { writable } from \"svelte/store\";\nimport { localStore } from \"./localStore.js\";\nimport type { TodoType } from \"./types/todo.type\";\n\nexport const alert = writable(\"Welcome to the To-Do list app!\");\n\nconst initialTodos: TodoType[] = [\n { id: 1, name: \"Visit MDN web docs\", completed: true },\n { id: 2, name: \"Complete the Svelte Tutorial\", completed: false },\n];\n\nexport const todos = localStore(\"mdn-svelte-todo\", initialTodos);\n</code></pre></div>\n</li>\n<li>\n<p>Remember to update the <code>import</code> statements in <code>App.svelte</code>, <code>Alert.svelte</code>, and <code>Todos.svelte</code>. Just remove the <code>.js</code> extension, like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>import { todos } from \"../stores\";\n</code></pre></div>\n</li>\n</ol>\n<p>Now onto <code>localStore.js</code>.</p>\n<p>Update the <code>import</code> statement in <code>stores.ts</code> like so:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>import { localStore } from \"./localStore\";\n</code></pre></div>\n<ol>\n<li>\n<p>Start by renaming the file to <code>localStore.ts</code>.</p>\n</li>\n<li>\n<p>TypeScript is telling us to specify the type of the <code>key</code>, <code>initial</code>, and <code>value</code> variables. The first one is easy: the key of our local web storage should be a string.</p>\n<p>But <code>initial</code> and <code>value</code> should be any object that could be converted to a valid JSON string with the <a href=\"/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify\"><code>JSON.stringify</code></a> method, meaning any JavaScript object with a couple limitations: for example, <code>undefined</code>, functions, and symbols are not valid JSON values.</p>\n<p>So we'll create the type <code>JsonValue</code> to specify these conditions.</p>\n<p>Create the file <code>json.type.ts</code> in the <code>types</code> folder.</p>\n</li>\n<li>\n<p>Give it the following content:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>export type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n</code></pre></div>\n<p>The <code>|</code> operator lets us declare variables that could store values of two or more types. A <code>JsonValue</code> could be a string, a number, a boolean, and so on. In this case we are also making use of recursive types to specify that a <code>JsonValue</code> can have an array of <code>JsonValue</code> and also an object with properties of type <code>JsonValue</code>.</p>\n</li>\n<li>\n<p>We will import our <code>JsonValue</code> type and use it accordingly. Update your <code>localStore.ts</code> file like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>// localStore.ts\nimport { writable } from \"svelte/store\";\n\nimport type { JsonValue } from \"./types/json.type\";\n\nexport const localStore = (key: string, initial: JsonValue) => {\n // receives the key of the local storage and an initial value\n\n const toString = (value: JsonValue) => JSON.stringify(value, null, 2); // helper function\n const toObj = JSON.parse; // helper function\n\n if (localStorage.getItem(key) === null) {\n // item not present in local storage\n localStorage.setItem(key, toString(initial)); // initialize local storage with initial value\n }\n\n const saved = toObj(localStorage.getItem(key)); // convert to object\n\n const { subscribe, set, update } = writable(saved); // create the underlying writable store\n\n return {\n subscribe,\n set: (value: JsonValue) => {\n localStorage.setItem(key, toString(value)); // save also to local storage as a string\n return set(value);\n },\n update,\n };\n};\n</code></pre></div>\n</li>\n</ol>\n<p>Now if we try to create a <code>localStore</code> with something that cannot be converted to JSON via <code>JSON.stringify()</code>, for example an object with a function as a property, VS Code/<code>validate</code> will complain about it:</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/11-vscode-invalid-store.png\" alt=\"VS Code showing an error with using our store — it fails when trying to set a local storage value to something incompatible with JSON stringify\" width=\"1314\" height=\"236\" loading=\"lazy\"></p>\n<p>And best of all, it will even work with the <a href=\"https://svelte.dev/docs/svelte-components#script-4-prefix-stores-with-$-to-access-their-values\" class=\"external\" target=\"_blank\"><code>$store</code> auto-subscription syntax</a>. If we try to save an invalid value to our <code>todos</code> store using the <code>$store</code> syntax, like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">svelte</span></div><pre class=\"brush: svelte notranslate\"><code><!-- App.svelte -->\n<script lang=\"ts\">\n import Todos from \"./components/Todos.svelte\";\n import Alert from \"./components/Alert.svelte\";\n\n import { todos } from \"./stores\";\n\n // this is invalid, the content cannot be converted to JSON using JSON.stringify\n $todos = { handler: () => {} };\n</script>\n</code></pre></div>\n<p>The check script will report the following error:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>> npm run check\n\nGetting Svelte diagnostics...\n====================================\n\n./svelte-todo-typescript/src/App.svelte:8:12\nError: Argument of type '{ handler: () => void; }' is not assignable to parameter of type 'JsonValue'.\n Types of property 'handler' are incompatible.\n Type '() => void' is not assignable to type 'JsonValue'.\n Type '() => void' is not assignable to type '{ [key: string]: JsonValue; }'.\n Index signature is missing in type '() => void'. (ts)\n $todos = { handler: () => {} }\n</code></pre></div>\n<p>This is another example of how specifying types can make our code more robust and help us catch more bugs before they get into production.</p>\n<p>And that's it. We've converted our whole application to use TypeScript.</p>"}},{"type":"prose","value":{"id":"bulletproofing_our_stores_with_generics","title":"Bulletproofing our stores with Generics","isH3":false,"content":"<p>Our stores have already been ported to TypeScript, but we can do better. We shouldn't need to store any kind of value — we know that the alert store should contain string messages, and the to-dos store should contain an array of <code>TodoType</code>, etc. We can let TypeScript enforce this using <a href=\"https://www.typescriptlang.org/docs/handbook/generics.html\" class=\"external\" target=\"_blank\">TypeScript Generics</a>. Let's find out more.</p>"}},{"type":"prose","value":{"id":"understanding_typescript_generics","title":"Understanding TypeScript generics","isH3":true,"content":"<p>Generics allow you to create reusable code components that work with a variety of types instead of a single type. They can be applied to interfaces, classes, and functions. Generic types are passed as parameters using a special syntax: they are specified within angle brackets and are conventionally denoted with a single uppercase letter. Generic types allow you to capture the types provided by the user, ensuring they're available for future processing.</p>\n<p>Let's see a quick example, a simple <code>Stack</code> class that lets us <code>push</code> and <code>pop</code> elements, like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>export class Stack {\n private elements = [];\n\n push = (element) => this.elements.push(element);\n\n pop() {\n if (this.elements.length === 0) throw new Error(\"The stack is empty!\");\n return this.elements.pop();\n }\n}\n</code></pre></div>\n<p>In this case <code>elements</code> is an array of type <code>any</code>, and accordingly the <code>push()</code> and <code>pop()</code> methods both receive and return a variable of type <code>any</code>. So it's perfectly valid to do something like the following:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>const anyStack = new Stack();\n\nanyStack.push(1);\nanyStack.push(\"hello\");\n</code></pre></div>\n<p>But what if we wanted to have a <code>Stack</code> that would only work with type <code>string</code>? We could do the following:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>export class StringStack {\n private elements: string[] = [];\n\n push = (element: string) => this.elements.push(element);\n\n pop(): string {\n if (this.elements.length === 0) throw new Error(\"The stack is empty!\");\n return this.elements.pop();\n }\n}\n</code></pre></div>\n<p>That would work. But if we wanted to work with numbers, we would then have to duplicate our code and create a <code>NumberStack</code> class. And how could we handle a stack of types we don't know yet, and that should be defined by the consumer?</p>\n<p>To solve all these problems, we can use generics.</p>\n<p>This is our <code>Stack</code> class reimplemented using generics:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>export class Stack<T> {\n private elements: T[] = [];\n\n push = (element: T): number => this.elements.push(element);\n\n pop(): T {\n if (this.elements.length === 0) throw new Error(\"The stack is empty!\");\n return this.elements.pop();\n }\n}\n</code></pre></div>\n<p>We define a generic type <code>T</code> and then use it like we would normally use a specific type. Now elements is an array of type <code>T</code>, and <code>push()</code> and <code>pop()</code> both receive and return a variable of type <code>T</code>.</p>\n<p>This is how we would use our generic <code>Stack</code>:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>const numberStack = new Stack<number>();\nnumberStack.push(1);\n</code></pre></div>\n<p>Now TypeScript knows that our stack can only accept numbers, and will issue an error if we try to push anything else:</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/12-vscode-generic-stack-error.png\" alt=\"Argument of type hello is not assignable to parameter of type number\" width=\"849\" height=\"232\" loading=\"lazy\"></p>\n<p>TypeScript can also infer generic types by its usage. Generics also support default values and constraints.</p>\n<p>Generics are a powerful feature that allows our code to abstract away from the specific types being used, making it more reusable and generic without giving up on type safety. To learn more about it, check out the <a href=\"https://www.typescriptlang.org/docs/handbook/generics.html\" class=\"external\" target=\"_blank\">TypeScript Introduction to Generics</a>.</p>"}},{"type":"prose","value":{"id":"using_svelte_stores_with_generics","title":"Using Svelte stores with generics","isH3":true,"content":"<p>Svelte stores support generics out of the box. And, because of generic type inference, we can take advantage of it without even touching our code.</p>\n<p>If you open the file <code>Todos.svelte</code> and assign a <code>number</code> type to our <code>$alert</code> store, you'll get the following error:</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/13-vscode-generic-alert-error.png\" alt=\"Argument of type 9999 is not assignable to parameter of type string\" width=\"808\" height=\"203\" loading=\"lazy\"></p>\n<p>That's because when we defined our alert store in the <code>stores.ts</code> file with:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">js</span></div><pre class=\"brush: js notranslate\"><code>export const alert = writable(\"Welcome to the To-Do list app!\");\n</code></pre></div>\n<p>TypeScript inferred the generic type to be <code>string</code>. If we wanted to be explicit about it, we could do the following:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>export const alert = writable<string>(\"Welcome to the To-Do list app!\");\n</code></pre></div>\n<p>Now we'll make our <code>localStore</code> store support generics. Remember that we defined the <code>JsonValue</code> type to prevent the usage of our <code>localStore</code> store with values that cannot be persisted using <code>JSON.stringify()</code>. Now we want the consumers of <code>localStore</code> to be able to specify the type of data to persist, but instead of working with any type, they should comply with the <code>JsonValue</code> type. We'll specify that with a Generic constraint, like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>export const localStore = <T extends JsonValue>(key: string, initial: T)\n</code></pre></div>\n<p>We define a generic type <code>T</code> and specify that it must be compatible with the <code>JsonValue</code> type. Then we'll use the <code>T</code> type appropriately.</p>\n<p>Our <code>localStore.ts</code> file will end up like this — try the new code now in your version:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>// localStore.ts\nimport { writable } from \"svelte/store\";\n\nimport type { JsonValue } from \"./types/json.type\";\n\nexport const localStore = <T extends JsonValue>(key: string, initial: T) => {\n // receives the key of the local storage and an initial value\n\n const toString = (value: T) => JSON.stringify(value, null, 2); // helper function\n const toObj = JSON.parse; // helper function\n\n if (localStorage.getItem(key) === null) {\n // item not present in local storage\n localStorage.setItem(key, toString(initial)); // initialize local storage with initial value\n }\n\n const saved = toObj(localStorage.getItem(key)); // convert to object\n\n const { subscribe, set, update } = writable<T>(saved); // create the underlying writable store\n\n return {\n subscribe,\n set: (value: T) => {\n localStorage.setItem(key, toString(value)); // save also to local storage as a string\n return set(value);\n },\n update,\n };\n};\n</code></pre></div>\n<p>And thanks to generic type inference, TypeScript already knows that our <code>$todos</code> store should contain an array of <code>TodoType</code>:</p>\n<p><img src=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript/14-vscode-generic-localstore-error.png\" alt=\"Todo Type object property complete should be completed\" width=\"1415\" height=\"147\" loading=\"lazy\"></p>\n<p>Once again, if we wanted to be explicit about it, we could do so in the <code>stores.ts</code> file like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">ts</span></div><pre class=\"brush: ts notranslate\"><code>const initialTodos: TodoType[] = [\n { id: 1, name: \"Visit MDN web docs\", completed: true },\n { id: 2, name: \"Complete the Svelte Tutorial\", completed: false },\n];\n\nexport const todos = localStore<TodoType[]>(\"mdn-svelte-todo\", initialTodos);\n</code></pre></div>\n<p>That will do for our brief tour of TypeScript Generics.</p>"}},{"type":"prose","value":{"id":"the_code_so_far","title":"The code so far","isH3":false,"content":""}},{"type":"prose","value":{"id":"git_2","title":"Git","isH3":true,"content":"<p>To see the state of the code as it should be at the end of this article, access your copy of our repo like this:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>cd mdn-svelte-tutorial/08-next-steps\n</code></pre></div>\n<p>Or directly download the folder's content:</p>\n<div class=\"code-example\"><div class=\"example-header\"><span class=\"language-name\">bash</span></div><pre class=\"brush: bash notranslate\"><code>npx degit opensas/mdn-svelte-tutorial/08-next-steps\n</code></pre></div>\n<p>Remember to run <code>npm install && npm run dev</code> to start your app in development mode.</p>"}},{"type":"prose","value":{"id":"repl_2","title":"REPL","isH3":true,"content":"<p>As we said earlier, TypeScript is not yet available in the REPL.</p>"}},{"type":"prose","value":{"id":"summary","title":"Summary","isH3":false,"content":"<p>In this article we took our to-do list application and ported it to TypeScript.</p>\n<p>We first learnt about TypeScript and what advantages it can bring us. Then we saw how to create a new Svelte project with TypeScript support. We also saw how to convert an existing Svelte project to use TypeScript — our to-do list app.</p>\n<p>We saw how to work with <a href=\"https://code.visualstudio.com/\" class=\"external\" target=\"_blank\">Visual Studio Code</a> and the <a href=\"https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode\" class=\"external\" target=\"_blank\">Svelte extension</a> to get features like type checking and auto-completion. We also used the <code>svelte-check</code> tool to inspect TypeScript issues from the command line.</p>\n<p>In the next article we will learn how to compile and deploy our app to production. We will also see which resources are available online to go further with learning Svelte.</p>\n<ul class=\"prev-next\"><li><a class=\"button secondary\" href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_stores\"><span class=\"button-wrap\"> Previous </span></a></li><li><a class=\"button secondary\" href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries\"><span class=\"button-wrap\"> Overview: JavaScript frameworks and libraries</span></a></li><li><a class=\"button secondary\" href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_deployment_next\"><span class=\"button-wrap\"> Next </span></a></li></ul>"}}],"isActive":true,"isMarkdown":true,"isTranslated":false,"locale":"en-US","mdn_url":"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript","modified":"2024-12-19T15:37:45.000Z","native":"English (US)","noIndexing":false,"other_translations":[{"locale":"de","title":"TypeScript-Unterstützung in Svelte","native":"Deutsch"},{"locale":"zh-CN","title":"Svelte 对 TypeScript 的支持","native":"中文 (简体)"}],"pageTitle":"TypeScript support in Svelte - Learn web development | MDN","parents":[{"uri":"/en-US/docs/Learn_web_development","title":"Learn"},{"uri":"/en-US/docs/Learn_web_development/Core","title":"Core learning modules"},{"uri":"/en-US/docs/Learn_web_development/Core/Frameworks_libraries","title":"JavaScript frameworks and libraries"},{"uri":"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Svelte_TypeScript","title":"TypeScript support in Svelte"}],"popularity":null,"short_title":"TypeScript support in Svelte","sidebarHTML":"<ol><li class=\"section\"><a href=\"/en-US/docs/Learn_web_development/Getting_started\">Getting started modules</a></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup\">Environment setup</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Installing_software\">Installing basic software</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Browsing_the_web\">Browsing the web</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Code_editors\">Code editors</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Dealing_with_files\">Dealing with files</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Environment_setup/Command_line\">Command line crash course</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Getting_started/Your_first_website\">Your first website</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Your_first_website/What_will_your_website_look_like\">What will your website look like?</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Creating_the_content\">HTML: Creating the content</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Styling_the_content\">CSS: Styling the content</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Adding_interactivity\">JavaScript: Adding interactivity</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Your_first_website/Publishing_your_website\">Publishing your website</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Getting_started/Web_standards\">Web standards</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Web_standards/How_the_web_works\">How the web works</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Web_standards/The_web_standards_model\">The web standards model</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Web_standards/How_browsers_load_websites\">How browsers load websites</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Getting_started/Soft_skills\">Soft skills</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Research_and_learning\">Research and learning</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Collaboration_and_teamwork\">Collaboration and teamwork</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Workflows_and_processes\">Workflows and processes</a></li><li><a href=\"/en-US/docs/Learn_web_development/Getting_started/Soft_skills/Job_interviews\">Succeeding in job interviews</a></li></ol></details></li><li class=\"section\"><a href=\"/en-US/docs/Learn_web_development/Core\">Core modules</a></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content\">Structuring content with HTML</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Basic_HTML_syntax\">Basic HTML syntax</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Webpage_metadata\">What's in the head? Webpage metadata</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Headings_and_paragraphs\">Headings and paragraphs in HTML</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Emphasis_and_importance\">Emphasis and importance</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Lists\">Lists</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Structuring_documents\">Structuring documents</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Advanced_text_features\">Advanced text features</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Creating_links\">Creating links</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Marking_up_a_letter\">Challenge: Marking up a letter</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Structuring_a_page_of_content\">Challenge: Structuring a page of content</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_images\">HTML images</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_video_and_audio\">HTML video and audio</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Mozilla_splash_page\">Challenge: Mozilla splash page</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_table_basics\">HTML table basics</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Table_accessibility\">HTML table accessibility</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Planet_data_table\">Challenge: Structuring a planet data table</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_forms\">Forms and buttons in HTML</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Structuring_content/Debugging_HTML\">Debugging HTML</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics\">CSS styling basics</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/What_is_CSS\">What is CSS?</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Getting_started\">Getting started with CSS</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Styling_a_bio_page\">Challenge: Styling a biography page</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Basic_selectors\">Basic CSS selectors</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Attribute_selectors\">Attribute selectors</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Pseudo_classes_and_elements\">Pseudo-classes and pseudo-elements</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Combinators\">Combinators</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Box_model\">The box model</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Handling_conflicts\">Handling conflicts</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Values_and_units\">CSS values and units</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Sizing\">Sizing items in CSS</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Backgrounds_and_borders\">Backgrounds and borders</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Overflow\">Overflowing content</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Images_media_forms\">Images, media, and form elements</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Tables\">Styling tables</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Debugging_CSS\">Debugging CSS</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Fundamental_CSS_comprehension\">Challenge: Fundamental CSS comprehension</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Fancy_letterheaded_paper\">Challenge: Creating fancy letterheaded paper</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Styling_basics/Cool-looking_box\">Challenge: A cool-looking box</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Core/Text_styling\">CSS text styling</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/Text_styling/Fundamentals\">Fundamental text and font styling</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Text_styling/Styling_lists\">Styling lists</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Text_styling/Styling_links\">Styling links</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Text_styling/Web_fonts\">Web fonts</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Text_styling/Typesetting_a_homepage\">Challenge: Typesetting a community school homepage</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout\">CSS layout</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Introduction\">Introduction to CSS layout</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Floats\">Floats</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Positioning\">Positioning</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Flexbox\">Flexbox</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Grids\">CSS grid layout</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Responsive_Design\">Responsive design</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Media_queries\">Media query fundamentals</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/CSS_layout/Fundamental_Layout_Comprehension\">Challenge: Fundamental layout comprehension</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Core/Scripting\">Dynamic scripting with JavaScript</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/What_is_JavaScript\">What is JavaScript?</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/A_first_splash\">A first splash into JavaScript</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/What_went_wrong\">What went wrong? Troubleshooting JavaScript</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Variables\">Storing the information you need — Variables</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Math\">Basic math in JavaScript — numbers and operators</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Strings\">Handling text — strings in JavaScript</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Useful_string_methods\">Useful string methods</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Arrays\">Arrays</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Silly_story_generator\">Challenge: Silly story generator</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Conditionals\">Making decisions in your code — conditionals</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Loops\">Looping code</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Functions\">Functions — reusable blocks of code</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Build_your_own_function\">Build your own function</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Return_values\">Function return values</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Events\">Introduction to events</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Event_bubbling\">Event bubbling</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Image_gallery\">Challenge: Image gallery</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Object_basics\">JavaScript object basics</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/DOM_scripting\">DOM scripting introduction</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Network_requests\">Making network requests with JavaScript</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/JSON\">Working with JSON</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Scripting/Debugging_JavaScript\">Debugging JavaScript and handling errors</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries\">JavaScript frameworks and libraries</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Introduction\">Introduction to client-side frameworks</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/Main_features\">Framework main features</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_getting_started\">Getting started with React</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_todo_list_beginning\">Beginning our React todo list</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_components\">Componentizing our React app</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_events_state\">React interactivity: Events and state</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_interactivity_filtering_conditional_rendering\">React interactivity: Editing, filtering, conditional rendering</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_accessibility\">Accessibility in React</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Frameworks_libraries/React_resources\">React resources</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility\">Accessibility</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/What_is_accessibility\">What is accessibility?</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/Tooling\">Accessibility tooling and assistive technology</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/HTML\">HTML: A good basis for accessibility</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/CSS_and_JavaScript\">CSS and JavaScript accessibility best practices</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/WAI-ARIA_basics\">WAI-ARIA basics</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/Multimedia\">Accessible multimedia</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/Mobile\">Mobile accessibility</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Accessibility/Accessibility_troubleshooting\">Challenge: Accessibility troubleshooting</a></li></ol></details></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Design_for_developers\">Design for developers</a></li><li><a href=\"/en-US/docs/Learn_web_development/Core/Version_control\">Version control</a></li><li class=\"section\"><a href=\"/en-US/docs/Learn_web_development/Extensions\">Extension modules</a></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects\">Advanced JavaScript objects</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_prototypes\">Object prototypes</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object-oriented_programming\">Object-oriented programming</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Classes_in_JavaScript\">Classes in JavaScript</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Object_building_practice\">Object building practice</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Advanced_JavaScript_objects/Adding_bouncing_balls_features\">Challenge: Adding features to our bouncing balls demo</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_APIs\">Client-side web APIs</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Introduction\">Introduction to web APIs</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Video_and_audio_APIs\">Video and Audio APIs</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Drawing_graphics\">Drawing graphics</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Client-side_storage\">Client-side storage</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_APIs/Third_party_APIs\">Third-party APIs</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Async_JS\">Asynchronous JavaScript</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Async_JS/Introducing\">Introducing asynchronous JavaScript</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Async_JS/Promises\">How to use promises</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Async_JS/Implementing_a_promise-based_API\">How to implement a promise-based API</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Async_JS/Introducing_workers\">Introducing workers</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Async_JS/Sequencing_animations\">Challenge: Sequencing animations</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms\">Web forms</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Your_first_form\">Your first form</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/How_to_structure_a_web_form\">How to structure a web form</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Basic_native_form_controls\">Basic native form controls</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/HTML5_input_types\">The HTML5 input types</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Other_form_controls\">Other form controls</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Styling_web_forms\">Styling web forms</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Advanced_form_styling\">Advanced form styling</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/UI_pseudo-classes\">UI pseudo-classes</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Form_validation\">Client-side form validation</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Forms/Sending_and_retrieving_form_data\">Sending form data</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_tools\">Understanding client-side tools</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Overview\">Client-side tooling overview</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Package_management\">Package management basics</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Introducing_complete_toolchain\">Introducing a complete toolchain</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Client-side_tools/Deployment\">Deploying our app</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side\">Server-side websites</a></summary><ol><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps\">Server-side first steps</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Introduction\">Introduction to the server side</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Client-Server_overview\">Client-Server Overview</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Web_frameworks\">Server-side web frameworks</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/First_steps/Website_security\">Website security</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django\">Django web framework (Python)</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Introduction\">Django introduction</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/development_environment\">Setting up a Django development environment</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Tutorial_local_library_website\">Django Tutorial: The Local Library website</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/skeleton_website\">Django Tutorial Part 2: Creating a skeleton website</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Models\">Django Tutorial Part 3: Using models</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Admin_site\">Django Tutorial Part 4: Django admin site</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Home_page\">Django Tutorial Part 5: Creating our home page</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Generic_views\">Django Tutorial Part 6: Generic list and detail views</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Sessions\">Django Tutorial Part 7: Sessions framework</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Authentication\">Django Tutorial Part 8: User authentication and permissions</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Forms\">Django Tutorial Part 9: Working with forms</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Testing\">Django Tutorial Part 10: Testing a Django web application</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/Deployment\">Django Tutorial Part 11: Deploying Django to production</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/web_application_security\">Django web application security</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Django/django_assessment_blog\">Assessment: DIY Django mini blog</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs\">Express web framework (Node.js)</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Introduction\">Express/Node introduction</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/development_environment\">Setting up a Node development environment</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Tutorial_local_library_website\">Express Tutorial: The Local Library website</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/skeleton_website\">Express Tutorial Part 2: Creating a skeleton website</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/mongoose\">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/routes\">Express Tutorial Part 4: Routes and controllers</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Displaying_data\">Express Tutorial Part 5: Displaying library data</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/forms\">Express Tutorial Part 6: Working with forms</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/deployment\">Express Tutorial Part 7: Deploying to production</a></li></ol></details></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance\">Web performance</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/why_web_performance\">The \"why\" of web performance</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/What_is_web_performance\">What is web performance?</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/Perceived_performance\">Perceived performance</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/Measuring_performance\">Measuring performance</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/Multimedia\">Multimedia: Images</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/video\">Multimedia: video</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/JavaScript\">JavaScript performance optimization</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/HTML\">HTML performance optimization</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/CSS\">CSS performance optimization</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Performance/business_case_for_performance\">The business case for web performance</a></li></ol></details></li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing\">Testing</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing/Introduction\">Introduction to cross-browser testing</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing/Testing_strategies\">Strategies for carrying out testing</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing/HTML_and_CSS\">Handling common HTML and CSS problems</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing/Feature_detection\">Implementing feature detection</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing/Automated_testing\">Introduction to automated testing</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Testing/Your_own_automation_environment\">Setting up your own test automation environment</a></li></ol></details></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Transform_animate\">Transform and animate CSS</a></li><li><a href=\"/en-US/docs/Learn_web_development/Extensions/Security_privacy\">Security and privacy</a></li><li class=\"section\">Further resources</li><li class=\"toggle\"><details><summary><a href=\"/en-US/docs/Learn_web_development/Howto\">How to solve common problems</a></summary><ol><li><a href=\"/en-US/docs/Learn_web_development/Howto/Solve_HTML_problems\">Solve common HTML problems</a></li><li><a href=\"/en-US/docs/Learn_web_development/Howto/Solve_CSS_problems\">Solve common CSS problems</a></li><li><a href=\"/en-US/docs/Learn_web_development/Howto/Solve_JavaScript_problems\">Solve common JavaScript problems</a></li><li><a href=\"/en-US/docs/Learn_web_development/Howto/Web_mechanics\">Web mechanics</a></li><li><a href=\"/en-US/docs/Learn_web_development/Howto/Tools_and_setup\">Tools and setup</a></li><li><a href=\"/en-US/docs/Learn_web_development/Howto/Design_and_accessibility\">Design and accessibility</a></li></ol></details></li><li><a href=\"/en-US/docs/Learn_web_development/About\">About</a></li><li><a href=\"/en-US/docs/Learn_web_development/Educators\">Resources for educators</a></li><li><a href=\"/en-US/docs/Learn_web_development/Changelog\">Changelog</a></li></ol>","source":{"folder":"en-us/learn_web_development/core/frameworks_libraries/svelte_typescript","github_url":"https://github.com/mdn/content/blob/main/files/en-us/learn_web_development/core/frameworks_libraries/svelte_typescript/index.md","last_commit_url":"https://github.com/mdn/content/commit/5b20f5f4265f988f80f513db0e4b35c7e0cd70dc","filename":"index.md"},"summary":"In the last article we learned about Svelte stores and even implemented our own custom store to persist the app's information to Web Storage. We also had a look at using the transition directive to implement animations on DOM elements in Svelte.","title":"TypeScript support in Svelte","toc":[{"text":"Code along with us","id":"code_along_with_us"},{"text":"TypeScript: optional static typing for JavaScript","id":"typescript_optional_static_typing_for_javascript"},{"text":"Why TypeScript?","id":"why_typescript"},{"text":"Creating a Svelte TypeScript project from scratch","id":"creating_a_svelte_typescript_project_from_scratch"},{"text":"Adding TypeScript support to an existing Svelte Project","id":"adding_typescript_support_to_an_existing_svelte_project"},{"text":"Improved developer experience with TypeScript","id":"improved_developer_experience_with_typescript"},{"text":"Creating a custom type","id":"creating_a_custom_type"},{"text":"Porting our to-do list app to TypeScript","id":"porting_our_to-do_list_app_to_typescript"},{"text":"Bulletproofing our stores with Generics","id":"bulletproofing_our_stores_with_generics"},{"text":"The code so far","id":"the_code_so_far"},{"text":"Summary","id":"summary"}],"pageType":"learn-module-chapter"}}</script></body></html>