Nós podemos usar a TypeScript dentro dos componentes da Svelte. Extensões de ambiente de desenvolvimento integrado como a extensão de VSCode da Svelte ajudar-nos-á a capturar os erros diretamente no nosso editor, e o svelte-check
faz o mesmo na linha de comando, o qual podemos integrar na nossa integração continua.
Configuraçãopermalink
Para usarmos a TypeScript dentro dos componentes da Svelte, precisamos adicionar um pré-processador que transformará a TypeScript em JavaScript.
Usando a SvelteKit ou a Vitepermalink
A maneira mais fácil de começar é estruturando um novo projeto de SvelteKit digitando npm create svelte@latest
, seguindo os prontos e escolhendo a opção TypeScript:
ts
import {vitePreprocess } from '@sveltejs/kit/vite';constconfig = {preprocess :vitePreprocess ()};export defaultconfig ;
Se não precisamos ou queremos todas as funcionalidades que a SvelteKit tem a oferecer, podemos estruturar um projeto de Vite temperado com a Svelte digitando npm create vite@latest
e selecionando a opção svelte-ts
:
ts
import {vitePreprocess } from '@sveltejs/vite-plugin-svelte';constconfig = {preprocess :vitePreprocess ()};export defaultconfig ;
Em ambos casos, um svelte.config.js
com vitePreprocess
será adicionado. A Vite ou a SvelteKit lerá a partir deste ficheiro de configuração.
Outras Ferramentas de Construçãopermalink
Se estivermos usando ferramentas como a Rollup ou a Webpack, instalamos as suas respetivas extensões de Svelte. Para a Rollup é rollup-plugin-svelte
e para a Webpack é svelte-loader
. Para ambas, precisamos instalar a typescript
e a svelte-preprocess
e adicionar o pré-processador à configuração da extensão (consulte as respetivas READMEs por mais informação). Se estivermos começando um novo projeto, também podemos usar o modelo de projeto da rollup
ou da webpack
para estruturar a configuração a partir dum programa.
Se estivermos a começar um novo projeto, recomendamos usar a SvelteKit ou Vite
<script lang="ts">permalink
Para usarmos a TypeScript dentro dos nossos componentes da Svelte, adicionamos lang="ts"
aos nossos marcadores de script
:
<script lang="ts">
let name: string = 'world';
function greet(name: string) {
alert(`Hello, ${name}!`);
}
</script>
Propriedadespermalink
As propriedades podem ser tipificadas diretamente sobre a declaração export let
:
<script lang="ts">
export let name: string;
</script>
Ranhuraspermalink
A ranhura e os tipos da propriedades do slot
são inferidos a partir dos tipos das propriedades da ranhura passadas às mesmas:
<script lang="ts">
export let name: string;
</script>
<slot {name} />
<!-- Depois -->
<Comp let:name>
<!-- ^ Inferido como sequência de caracteres -->
{name}
</Comp>
Eventospermalink
Os eventos podem ser tipificados com createEventDispatcher
:
<script lang="ts">
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher<{
event: null; // não aceita uma carga
click: string; // tem uma carga de sequência de caracteres obrigatória
type: string | null; // tem uma carga de sequência de caracteres opcional
}>();
function handleClick() {
dispatch('event');
dispatch('click', 'hello');
}
function handleType() {
dispatch('event');
dispatch('type', Math.random() > 0.5 ? 'world' : null);
}
</script>
<button on:click={handleClick} on:keydown={handleType}>Click</button>
Melhorando os Tipos do DOM Embutidospermalink
A Svelte fornece um melhor esforço para todos os tipos do DOM de HTML que existem. Algumas vezes podemos desejar usar atributos experimentais ou eventos personalizados vindos a partir duma ação. Se for um atributo ou evento padrão não experimental, este pode muito bem uma tipificação em falta da nossas tipificações de HTML. Neste caso, todos são bem-vindos a abrir uma questão ou um pedido de atualização do repositório para correção.
No caso que for um evento ou atributo experimental ou personalizado, podemos melhor as tipificações com isto:
ts
declare namespacesvelteHTML {// melhorar os elementosinterfaceIntrinsicElements {'my-custom-element': {someattribute : string; 'on:event': (e :CustomEvent <any>) => void };}// melhorar os atributosinterfaceHTMLAttributes <T > {// Se quisermos usar `on:beforeinstallprompt`'on:beforeinstallprompt'?: (event : any) => any;// Se quisermos usar `myCustomAttribute={..}` (nota: tudo minúsculo)mycustomattribute ?: any; // Podemos substituir `any` por algo mais específico se quisermos}}
Depois certificamos-nos de que o ficheiro d.ts
é referenciando no nosso tsconfig.json
. Se este precisar de algo como "include": ["src/**/*"]
e o nosso ficheiro d.ts
estiver dentro de src
, deve funcionar. Nós podemos precisar recarregar para as mudanças surtirem efeito.
Desde a versão 4.2 da Svelte ou versão 3.5 do svelte-check
ou versão 107.10.0 da extensão do VSCode também podemos declarar as tipificações aumentando o módulo svelte/elements
desta maneira:
ts
import {HTMLButtonAttributes } from 'svelte/elements';declare module 'svelte/elements' {export interfaceSvelteHTMLElements {'custom-button':HTMLButtonAttributes ;}// permite controle mais granular sobre para qual elemento adicionar as tipificaçõesexport interfaceHTMLButtonAttributes {veryexperimentalattribute ?: string;}}export {}; // garantir que isto não é um módulo ambiente, senão os tipos serão sobrepostos ao invés de aumentados
Tipificações Avançadas Experimentaispermalink
Algumas funcionalidades não estão tirando total vantagem da TypeScript nos casos de uso mais avançados como tipificar que um componente implementa uma certa interface, explicitamente tipificando as ranhuras, ou usando os genéricos. Estas coisas são possíveis usando as capacidades de tipo avançado experimentais. Consulte esta RFC por mais informação sobre como fazer uso das mesmas.
A API é experimental e pode mudar em algum ponto.
Limitaçõespermalink
Sem TypeScript na Marcaçãopermalink
Nós não podemos usar TypeScript na marcação do nosso modelo de marcação de hipertexto. Por exemplo, o seguinte não funciona:
<script lang="ts">
let count = 10;
</script>
<h1>Count as string: {count as string}!</h1> <!-- ❌ Não funciona -->
{#if count > 4}
{@const countString: string = count} <!-- ❌ Não funciona -->
{countString}
{/if}
Declarações Reativaspermalink
Nós não podemos tipificar as nossas declarações reativas com a TypeScript da maneira que tipificamos uma variável. Por exemplo, o seguinte não funciona:
<script lang="ts">
let count = 0;
$: doubled: number = count * 2; // ❌ Não funciona
</script>
Não podemos adicionar um : TYPE
porque é sintaxe inválida nesta posição. No lugar disto, podemos mover a definição para uma declaração de let
como acima:
<script lang="ts">
let count = 0;
let doubled: number;
$: doubled = count * 2;
</script>
Tipospermalink
ComponentConstructorOptionspermalink
Svelte components were classes in Svelte 4. In Svelte 5, thy are not anymore. Use
mount
orcreateRoot
instead to instantiate components. See breaking changes for more info.
ts
interface ComponentConstructorOptions<Props extends Record<string, any> = Record<string, any>> {…}
ts
target: Element | Document | ShadowRoot;
ts
anchor?: Element;
ts
props?: Props;
ts
context?: Map<any, any>;
ts
hydrate?: boolean;
ts
intro?: boolean;
ts
$$inline?: boolean;
ComponentEventspermalink
Convenience type to get the events the given component expects. Example:
<script lang="ts">
import type { ComponentEvents } from 'svelte';
import Component from './Component.svelte';
function handleCloseEvent(event: ComponentEvents<Component>['close']) {
console.log(event.detail);
}
</script>
<Component on:close={handleCloseEvent} />
ts
type ComponentEvents<Comp extends SvelteComponent> =Comp extends SvelteComponent<any, infer Events>? Events: never;
ComponentPropspermalink
Convenience type to get the props the given component expects. Example:
<script lang="ts">
import type { ComponentProps } from 'svelte';
import Component from './Component.svelte';
const props: ComponentProps<Component> = { foo: 'bar' }; // Errors if these aren't the correct props
</script>
ts
type ComponentProps<Comp extends SvelteComponent> =Comp extends SvelteComponent<infer Props> ? Props : never;
ComponentTypepermalink
Convenience type to get the type of a Svelte component. Useful for example in combination with
dynamic components using <svelte:component>
.
Example:
<script lang="ts">
import type { ComponentType, SvelteComponent } from 'svelte';
import Component1 from './Component1.svelte';
import Component2 from './Component2.svelte';
const component: ComponentType = someLogic() ? Component1 : Component2;
const componentOfCertainSubType: ComponentType<SvelteComponent<{ needsThisProp: string }>> = someLogic() ? Component1 : Component2;
</script>
<svelte:component this={component} />
<svelte:component this={componentOfCertainSubType} needsThisProp="hello" />
ts
type ComponentType<Comp extends SvelteComponent = SvelteComponent> = (new (options: ComponentConstructorOptions<Comp extends SvelteComponent<infer Props>? Props: Record<string, any>>) => Comp) & {/** The custom element version of the component. Only present if compiled with the `customElement` compiler option */element?: typeof HTMLElement;};
EventDispatcherpermalink
ts
interface EventDispatcher<EventMap extends Record<string, any>> {…}
ts
<Type extends keyof EventMap>(...args: null extends EventMap[Type]? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions]: undefined extends EventMap[Type]? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions]: [type: Type, parameter: EventMap[Type], options?: DispatchOptions]): boolean;
Snippetpermalink
The type of a #snippet
block. You can use it to (for example) express that your component expects a snippet of a certain type:
ts
let {banner } =$props <{banner :Snippet <{text : string }> }>();
You can only call a snippet through the {@render ...}
tag.
ts
interface Snippet<T = void> {…}
ts
(arg: T): typeof SnippetReturn & {_: 'functions passed to {@render ...} tags must use the `Snippet` type imported from "svelte"';};
SvelteComponentpermalink
Can be used to create strongly typed Svelte components.
Example:permalink
You have component library on npm called component-library
, from which
you export a component called MyComponent
. For Svelte+TypeScript users,
you want to provide typings. Therefore you create a index.d.ts
:
ts
Typing this makes it possible for IDEs like VS Code with the Svelte extension to provide intellisense and to use the component like this in a Svelte file with TypeScript:
<script lang="ts">
import { MyComponent } from "component-library";
</script>
<MyComponent foo={'bar'} />
This was the base class for Svelte components in Svelte 4. Svelte 5+ components
are completely different under the hood. You should only use this type for typing,
not actually instantiate components with new
- use mount
or createRoot
instead.
See breaking changes
for more info.
ts
class SvelteComponent<Props extends Record<string, any> = any,Events extends Record<string, any> = any,Slots extends Record<string, any> = any> {…}
ts
[prop: string]: any;
ts
constructor(options: ComponentConstructorOptions<PropsWithChildren<Props, Slots>>);
- deprecated This constructor only exists when using the
asClassComponent
compatibility helper, which is a stop-gap solution. Migrate towards usingmount
orcreateRoot
instead. See https://svelte-5-preview.vercel.app/docs/breaking-changes#components-are-no-longer-classes for more info.
ts
$destroy(): void;
- deprecated This method only exists when using one of the legacy compatibility helpers, which is a stop-gap solution. See https://svelte-5-preview.vercel.app/docs/breaking-changes#components-are-no-longer-classes for more info.
ts
$on<K extends Extract<keyof Events, string>>(type: K,callback: (e: Events[K]) => void): () => void;
- deprecated This method only exists when using one of the legacy compatibility helpers, which is a stop-gap solution. See https://svelte-5-preview.vercel.app/docs/breaking-changes#components-are-no-longer-classes for more info.
ts
$set(props: Partial<Props>): void;
- deprecated This method only exists when using one of the legacy compatibility helpers, which is a stop-gap solution. See https://svelte-5-preview.vercel.app/docs/breaking-changes#components-are-no-longer-classes for more info.
SvelteComponentTypedpermalink
Use
SvelteComponent
instead. See TODO for more information.
ts
class SvelteComponentTyped<Props extends Record<string, any> = any,Events extends Record<string, any> = any,Slots extends Record<string, any> = any