<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Isaac Muniz</title>
    <description>The latest articles on DEV Community by Isaac Muniz (@imuniz).</description>
    <link>https://dev.to/imuniz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2215659%2Ffc3e7d52-f9a1-438c-addd-78b1491bd850.jpg</url>
      <title>DEV Community: Isaac Muniz</title>
      <link>https://dev.to/imuniz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/imuniz"/>
    <language>en</language>
    <item>
      <title>Mapped Types em TypeScript: gerando tipos derivados de outros tipos</title>
      <dc:creator>Isaac Muniz</dc:creator>
      <pubDate>Tue, 07 Jul 2026 20:39:00 +0000</pubDate>
      <link>https://dev.to/imuniz/mapped-types-em-typescript-gerando-tipos-derivados-de-outros-tipos-3j79</link>
      <guid>https://dev.to/imuniz/mapped-types-em-typescript-gerando-tipos-derivados-de-outros-tipos-3j79</guid>
      <description>&lt;p&gt;Em algum momento todo projeto TypeScript chega nesse ponto: você já tem um tipo que descreve um objeto, e agora precisa de uma variação dele. Quase igual, mas com todos os campos opcionais. Ou com todos os campos aceitando &lt;code&gt;null&lt;/code&gt;. Ou com todos somente leitura.&lt;/p&gt;

&lt;p&gt;A solução ingênua é copiar o tipo e ajustar campo por campo, na mão. Funciona, até o tipo original ganhar um campo novo. A cópia não acompanha sozinha, e nada te avisa disso.&lt;/p&gt;

&lt;p&gt;Mapped types são a resposta do TypeScript para esse problema: em vez de reescrever cada campo, você descreve a transformação uma vez e manda o compilador percorrer todas as chaves de um tipo existente aplicando ela automaticamente. Adicione um campo ao tipo original, e toda variação construída a partir dele se atualiza sozinha no próximo compile, sem edição manual nenhuma.&lt;/p&gt;

&lt;p&gt;Só o &lt;code&gt;type&lt;/code&gt; consegue expressar isso. Um &lt;code&gt;interface&lt;/code&gt; não tem mecanismo equivalente, e no final deste artigo vai ficar claro exatamente por quê.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Perto do final deste artigo você vai encontrar links para o &lt;a href="https://www.typescriptlang.org/play" rel="noopener noreferrer"&gt;TypeScript Playground&lt;/a&gt; oficial, com o código já pronto para rodar sem precisar instalar nada. Se preferir, também pode ir copiando os exemplos abaixo e testando na sua própria IDE ao longo da leitura.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Antes de chegar lá, uma passada rápida por três conceitos que este artigo assume que você já conhece: object types, union types e string literal types. Se você já domina os três, pule direto para a próxima seção.&lt;/p&gt;

&lt;h2&gt;
  
  
  As três peças de base
&lt;/h2&gt;

&lt;p&gt;Um &lt;strong&gt;object type&lt;/strong&gt; descreve a forma de um objeto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Um &lt;strong&gt;union type&lt;/strong&gt; descreve um valor que pode ser de mais de um tipo, separados por &lt;code&gt;|&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MaybeNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Um &lt;strong&gt;string literal type&lt;/strong&gt; é quando um texto específico vira um tipo em si, não apenas um &lt;code&gt;string&lt;/code&gt; genérico:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;OnlyId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E os três se combinam: &lt;code&gt;"id" | "minutes"&lt;/code&gt; é uma union de string literal types, um tipo que aceita exatamente esses dois textos e nenhum outro. Esses três conceitos são a chave para entender os próximos.&lt;/p&gt;

&lt;h2&gt;
  
  
  O problema que os mapped types resolvem
&lt;/h2&gt;

&lt;p&gt;Volte ao &lt;code&gt;Entry&lt;/code&gt; acima. Suponha que você precise de um segundo tipo quase idêntico, mas em que todo campo também pode ser &lt;code&gt;null&lt;/code&gt; (um rascunho de formulário antes do usuário preencher, por exemplo). Sem nenhuma ferramenta especial, você escreve na mão, campo por campo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Manual, campo por campo: cada campo repetido e transformado na mão.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NullableEntryManual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NullableEntryManual&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// null 90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Funciona, e para dois campos está de bom tamanho. Mas repare que você digitou &lt;code&gt;id&lt;/code&gt; e &lt;code&gt;minutes&lt;/code&gt; pela segunda vez, e aplicou a mesma transformação, adicionar &lt;code&gt;| null&lt;/code&gt;, em cada um dos campos, na mão. Se &lt;code&gt;Entry&lt;/code&gt; ganhar um terceiro campo depois, o &lt;code&gt;NullableEntryManual&lt;/code&gt; não se atualiza sozinho. Você teria que lembrar de voltar nele e editar também, e nada te avisa se você esquecer.&lt;/p&gt;

&lt;p&gt;É esse acoplamento frágil que o mapped type elimina. Mas para chegar na sintaxe dele, precisamos de duas peças menores primeiro. Ambas só existem no TypeScript, nunca em código JavaScript comum.&lt;/p&gt;

&lt;h2&gt;
  
  
  Primeira peça: o operador keyof
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;keyof&lt;/code&gt; é uma palavra-chave &lt;strong&gt;exclusiva do TypeScript&lt;/strong&gt;. Ela não existe em JavaScript. Como todo tipo aqui, ela é apagada antes do JavaScript ser emitido, então tem custo zero em tempo de execução. Ela existe só para o compilador raciocinar sobre os seus tipos.&lt;/p&gt;

&lt;p&gt;O que ela faz é simples: &lt;code&gt;keyof&lt;/code&gt; recebe um &lt;strong&gt;object type&lt;/strong&gt; e produz a &lt;strong&gt;união dos nomes das chaves dele&lt;/strong&gt;, como string literal types.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// keyof lê um object type e produz a união dos nomes de suas chaves.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;EntryKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// equivale a "id" | "minutes"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EntryKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entryKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repare que aqui aparecem as duas peças da seção anterior juntas: &lt;code&gt;keyof Entry&lt;/code&gt; é uma &lt;strong&gt;union&lt;/strong&gt; de &lt;strong&gt;string literal types&lt;/strong&gt;. Nada é transformado ainda. &lt;code&gt;keyof Entry&lt;/code&gt; só responde a pergunta "quais são os nomes dos campos desse tipo, como uma união?".&lt;/p&gt;

&lt;p&gt;Você pode provar que a resposta é exata, e não apenas "qualquer string", tentando uma chave que não existe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;EntryKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;invalidEntryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EntryKeys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;other&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// não compila&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso não compila. O TypeScript rejeita com:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="nx"&gt;TS2322&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Type&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;"other"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;not&lt;/span&gt; &lt;span class="nx"&gt;assignable&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keyof Entry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso confirma que &lt;code&gt;keyof Entry&lt;/code&gt; é mesmo o conjunto fechado &lt;code&gt;"id" | "minutes"&lt;/code&gt;, calculado a partir do próprio &lt;code&gt;Entry&lt;/code&gt; em vez de escrito à mão.&lt;/p&gt;

&lt;h2&gt;
  
  
  Segunda peça: indexed access
&lt;/h2&gt;

&lt;p&gt;Se o &lt;code&gt;keyof&lt;/code&gt; responde "quais são as chaves", um &lt;strong&gt;indexed access type&lt;/strong&gt; responde "qual é o tipo do valor guardado nesta chave". Essa peça tem um significado exclusivo do TypeScript montado em cima de um símbolo com cara de JavaScript: os colchetes &lt;code&gt;[...]&lt;/code&gt; são exatamente os mesmos que o JavaScript usa para ler uma propriedade em tempo de execução (&lt;code&gt;entry["minutes"]&lt;/code&gt;), mas aqui, escritos depois de um nome de tipo em vez de uma variável, eles rodam inteiramente em tempo de compilação e produzem um tipo, não um valor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Indexed access: lê o tipo do valor guardado em uma chave.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;IdType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// string&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;MinutesType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;minutes&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// number&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;idValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;IdType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;e1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minutesValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MinutesType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;idValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;minutesValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// e1 42&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Entry["minutes"]&lt;/code&gt; não está lendo um valor em tempo de execução, &lt;code&gt;Entry&lt;/code&gt; é um tipo, não um objeto, então não há nada a ler. Ele está perguntando ao compilador: "no tipo &lt;code&gt;Entry&lt;/code&gt;, qual tipo está guardado sob a chave &lt;code&gt;"minutes"&lt;/code&gt;?". A resposta vira um tipo próprio, &lt;code&gt;number&lt;/code&gt;, que você pode usar em qualquer lugar onde um tipo é esperado.&lt;/p&gt;

&lt;h2&gt;
  
  
  Juntando as duas peças
&lt;/h2&gt;

&lt;p&gt;Antes de olhar a sintaxe completa do mapped type, vale separar os dois símbolos que ela usa: as chaves &lt;code&gt;{ }&lt;/code&gt; externas e os colchetes &lt;code&gt;[ ]&lt;/code&gt; internos. Nenhum dos dois faz nada que você ainda não tenha visto, uma vez isolados.&lt;/p&gt;

&lt;h3&gt;
  
  
  As chaves &lt;code&gt;{ }&lt;/code&gt; externas não têm nada de novo
&lt;/h3&gt;

&lt;p&gt;Todo object type que você escreveu até aqui veio embrulhado em chaves: &lt;code&gt;{ x: number; y: number }&lt;/code&gt;, &lt;code&gt;{ id: string; minutes: number }&lt;/code&gt;. Um mapped type continua sendo um object type, então continua começando e terminando com &lt;code&gt;{ }&lt;/code&gt;. Nada muda aí.&lt;/p&gt;

&lt;h3&gt;
  
  
  O &lt;code&gt;[ ]&lt;/code&gt; interno não é um array
&lt;/h3&gt;

&lt;p&gt;Essa é a parte que parece estranha, então vale ancorar em algo que você provavelmente já conhece do JavaScript puro: &lt;strong&gt;computed property names&lt;/strong&gt;. Em um object literal, se você quer que o nome de uma propriedade venha de uma variável em vez de ser digitado literalmente, você embrulha essa variável em colchetes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// JavaScript puro, sem TypeScript ainda.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;e1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// { id: 'e1' }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Aqui, &lt;code&gt;[key]&lt;/code&gt; não está criando um array. Ele fica no &lt;em&gt;lugar do nome da propriedade&lt;/em&gt; dentro do object literal, e diz ao JavaScript "use o valor da variável &lt;code&gt;key&lt;/code&gt; como o nome desta propriedade", em vez de "a propriedade se chama literalmente &lt;code&gt;key&lt;/code&gt;". Sem os colchetes, &lt;code&gt;{ key: "e1" }&lt;/code&gt; criaria uma propriedade chamada literalmente &lt;code&gt;key&lt;/code&gt;, o que é outra coisa completamente diferente.&lt;/p&gt;

&lt;p&gt;Um mapped type reutiliza exatamente esse mesmo lugar, a posição do nome da propriedade dentro das chaves &lt;code&gt;{ }&lt;/code&gt;. A diferença é que, em vez de calcular um único nome a partir de uma variável, como &lt;code&gt;[key]&lt;/code&gt; fez, ele varre uma união inteira de chaves, uma de cada vez, usando duas peças novas.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Toggles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;darkMode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compactView&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A primeira peça é o &lt;code&gt;K&lt;/code&gt;. Ele não é uma palavra reservada, é só um nome escolhido por você, do mesmo jeito que &lt;code&gt;key&lt;/code&gt; era um nome escolhido no exemplo em JavaScript. Na verdade, é o mesmo papel que a variável de um loop &lt;code&gt;for...of&lt;/code&gt; exerce em JavaScript: em &lt;code&gt;for (const item of list) { ... }&lt;/code&gt;, &lt;code&gt;item&lt;/code&gt; é só um nome guardando o valor atual da iteração, e você poderia chamá-lo de qualquer coisa. &lt;code&gt;K&lt;/code&gt; funciona igual, só que guarda a chave atual em vez de um item de lista. Poderia se chamar &lt;code&gt;Prop&lt;/code&gt; ou &lt;code&gt;Name&lt;/code&gt; sem mudar nada no resultado, mas a convenção da comunidade TypeScript é usar &lt;code&gt;K&lt;/code&gt; (de "key"), e é isso que você vai encontrar no dia a dia.&lt;/p&gt;

&lt;p&gt;A segunda peça é o &lt;code&gt;in&lt;/code&gt;. É ele quem faz o trabalho de repetição: &lt;code&gt;K in UNION&lt;/code&gt; significa "para cada membro da união &lt;code&gt;UNION&lt;/code&gt;, rode esta linha uma vez, chamando o membro atual de &lt;code&gt;K&lt;/code&gt;". É o &lt;code&gt;in&lt;/code&gt; que transforma uma união estática em uma sequência de rodadas, uma por chave.&lt;/p&gt;

&lt;p&gt;Leia a linha completa juntando as duas peças:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;{ }&lt;/code&gt; diz "isto é um object type", como sempre.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[K in "darkMode" | "compactView"]&lt;/code&gt; diz "para cada string literal type dentro desta união, rode uma vez, chamando o valor atual de &lt;code&gt;K&lt;/code&gt;, e use essa string literal como nome da propriedade desta rodada".&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Cuidado para não confundir com o outro &lt;code&gt;in&lt;/code&gt;:&lt;/strong&gt; o JavaScript já tem um operador &lt;code&gt;in&lt;/code&gt; que checa se um objeto tem uma certa propriedade, como em &lt;code&gt;"id" in someObject&lt;/code&gt;. É um operador diferente. O &lt;code&gt;in&lt;/code&gt; do mapped type só existe dentro dessa posição de colchete, em tempo de compilação, e some depois que o TypeScript vira JavaScript.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ou seja, essa única linha está fazendo duas rodadas do mesmo template: uma com &lt;code&gt;K = "darkMode"&lt;/code&gt;, outra com &lt;code&gt;K = "compactView"&lt;/code&gt;, e cada rodada cria uma propriedade, &lt;code&gt;darkMode: boolean&lt;/code&gt; e &lt;code&gt;compactView: boolean&lt;/code&gt;, usando o tipo depois dos dois pontos como tipo de valor para as duas. O resultado é exatamente &lt;code&gt;{ darkMode: boolean; compactView: boolean }&lt;/code&gt;, só que gerado mecanicamente em vez de digitado na mão.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do union escrito à mão para keyof
&lt;/h3&gt;

&lt;p&gt;Agora troque a união escrita à mão por &lt;code&gt;keyof Entry&lt;/code&gt;, para que as chaves venham de um tipo existente em vez de serem listadas na mão, e use indexed access para que cada propriedade mantenha o seu tipo original em vez de um tipo fixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Mapped type sem transformação: percorre cada chave de Entry mantendo o tipo &lt;/span&gt;
&lt;span class="c1"&gt;// do valor.&lt;/span&gt;
&lt;span class="c1"&gt;// O resultado é um tipo novo, mas com forma indistinguível de Entry.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;EntryCopy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entryCopy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EntryCopy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;e1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;backToEntry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entryCopy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// intercambiáveis, mesma forma&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entryCopy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;entryCopy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;backToEntry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// e1 90 90&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O que &lt;code&gt;{ [K in keyof Entry]: Entry[K] }&lt;/code&gt; faz, passo a passo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;keyof Entry&lt;/code&gt; calcula &lt;code&gt;"id" | "minutes"&lt;/code&gt;, o conjunto de chaves a percorrer.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;[K in ...]&lt;/code&gt; percorre essa união um membro de cada vez, chamando o membro atual de &lt;code&gt;K&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Para cada &lt;code&gt;K&lt;/code&gt;, &lt;code&gt;Entry[K]&lt;/code&gt; busca o tipo de valor original naquela mesma chave.&lt;/li&gt;
&lt;li&gt;O resultado é uma propriedade nova, chamada &lt;code&gt;K&lt;/code&gt;, tipada exatamente como estava em &lt;code&gt;Entry&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Esse mapped type em particular não muda nada, ele reproduz &lt;code&gt;Entry&lt;/code&gt; campo por campo, e por isso pode ser chamado de &lt;strong&gt;mapped type sem transformação&lt;/strong&gt;. Ele existe aqui só para isolar o mecanismo antes do próximo passo mexer nele.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adicionando a transformação
&lt;/h2&gt;

&lt;p&gt;O ponto inteiro de um mapped type é que o passo 4 acima, &lt;code&gt;Entry[K]&lt;/code&gt;, não precisa ficar intocado. Você pode embrulhar ele em qualquer coisa, e esse embrulho é aplicado a cada chave automaticamente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NullableEntry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Agora &lt;code&gt;Entry[K] | null&lt;/code&gt; significa "qualquer que fosse o tipo original deste campo, ou &lt;code&gt;null&lt;/code&gt;". Como isso é calculado uma vez e aplicado a toda chave, não importa se &lt;code&gt;Entry&lt;/code&gt; tem dois campos ou vinte: &lt;code&gt;NullableEntry&lt;/code&gt; acompanha sozinho, sem nenhuma edição manual.&lt;/p&gt;

&lt;p&gt;Compare com o &lt;code&gt;NullableEntryManual&lt;/code&gt; lá do começo. O resultado é o mesmo, mas agora a transformação está descrita em um lugar só, e ela acompanha o &lt;code&gt;Entry&lt;/code&gt; para sempre.&lt;/p&gt;

&lt;h2&gt;
  
  
  Por que isso importa: Partial, Readonly e companhia
&lt;/h2&gt;

&lt;p&gt;Toda transformação campo por campo que você possa querer: deixar todos os campos opcionais, deixar todos somente leitura, deixar todos aceitando &lt;code&gt;null&lt;/code&gt;, é um mapped type no fundo. Os &lt;a href="https://www.typescriptlang.org/docs/handbook/utility-types.html" rel="noopener noreferrer"&gt;utility types&lt;/a&gt; que o TypeScript já traz prontos, como &lt;code&gt;Partial&amp;lt;T&amp;gt;&lt;/code&gt;, &lt;code&gt;Required&amp;lt;T&amp;gt;&lt;/code&gt;, &lt;code&gt;Readonly&amp;lt;T&amp;gt;&lt;/code&gt; e &lt;code&gt;Record&amp;lt;K, V&amp;gt;&lt;/code&gt;, não são mágica especial do compilador: são mapped types comuns, já prontos pelo TypeScript, para você não precisar reescrever toda vez.&lt;/p&gt;

&lt;p&gt;Como amostra, o &lt;code&gt;Partial&amp;lt;T&amp;gt;&lt;/code&gt; é mais ou menos isso:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Uma versão manual e aproximada do que o Partial&amp;lt;T&amp;gt; te dá.&lt;/span&gt;
&lt;span class="c1"&gt;// O ? aqui é o modificador de opcional: ele pode ser aplicado dentro de um&lt;/span&gt;
&lt;span class="c1"&gt;// mapped type do mesmo jeito que se aplica a um campo normal.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PartialEntry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;]?:&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// O Partial&amp;lt;T&amp;gt; nativo do TypeScript faz exatamente a mesma coisa por baixo dos panos.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;PartialEntryBuiltIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PartialEntry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// id pode ficar de fora&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;builtInPatch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PartialEntryBuiltIn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt; &lt;span class="c1"&gt;// mesmo resultado&lt;/span&gt;

&lt;span class="c1"&gt;// Como os dois tipos têm a mesma forma, o valor de um serve perfeitamente como &lt;/span&gt;
&lt;span class="c1"&gt;// o outro.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PartialEntry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;builtInPatch&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;patch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;builtInPatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 45 45 45&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;?&lt;/code&gt; é a novidade aqui. Ele é o modificador de opcional, e a única razão de mostrá-lo agora é para que, quando você esbarrar no &lt;code&gt;Partial&amp;lt;T&amp;gt;&lt;/code&gt; no dia a dia, ele seja reconhecível como "o mecanismo de mapped type que você já conhece, mais um modificador", e não uma ideia inteiramente nova. Rode o arquivo você mesmo e veja: &lt;code&gt;PartialEntry&lt;/code&gt; e &lt;code&gt;PartialEntryBuiltIn&lt;/code&gt; são intercambiáveis, porque são o mesmo mapped type escrito de duas formas.&lt;/p&gt;

&lt;h2&gt;
  
  
  O arquivo completo
&lt;/h2&gt;

&lt;p&gt;Tudo acima se resume nos dois casos abaixo: um mapped type sobre uma união de chaves explícita, e um mapped type sobre &lt;code&gt;keyof&lt;/code&gt; com uma transformação. É um arquivo que você pode rodar com &lt;code&gt;npx tsc&lt;/code&gt; e depois &lt;code&gt;node&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
  Mapped type: constrói um tipo novo percorrendo um conjunto de chaves.
*/&lt;/span&gt;

&lt;span class="c1"&gt;// ---&lt;/span&gt;

&lt;span class="c1"&gt;// Caso A: percorre um conjunto explícito de chaves,&lt;/span&gt;
&lt;span class="c1"&gt;// dando a cada uma o mesmo tipo de valor.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Toggles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;darkMode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;compactView&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Toggles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;darkMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;compactView&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;darkMode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compactView&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true false&lt;/span&gt;

&lt;span class="c1"&gt;// ---&lt;/span&gt;

&lt;span class="c1"&gt;// Caso B: percorre as chaves de um tipo existente, transformando cada valor.&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nl"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;NullableEntry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;Entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;K&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NullableEntry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;90&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// null 90&lt;/span&gt;

&lt;span class="c1"&gt;// ---&lt;/span&gt;

&lt;span class="cm"&gt;/*
  Um corpo de interface não aceita a forma [K in ...] de mapped type.
  Se você descomentar a linha abaixo e rodar npx tsc, recebe:

  error TS1169: A computed property name in an interface must refer to
  an expression whose type is a literal type or a 'unique symbol' type.
*/&lt;/span&gt;
&lt;span class="c1"&gt;// interface TogglesIface { [K in "darkMode" | "compactView"]: boolean }&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A saída é:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;true false
null 90
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Deixei esse mesmo código disponível, pronto para você rodar, sem precisar instalar nada.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔗 &lt;a href="https://www.typescriptlang.org/play/?#code/PQKgUABBCyCGAO8CmATCAXAnsgXBAxgPYB2AzugE4DPAlhAK4C2GN8hExhAbu8hURQpJiKdkwIkAVvWLp2KJAQAWsLklIA6MCGBgwwYBAC0JvQYgBhWKXYBBPHwFCGzIsWmz2SAB7wANgC3+DRyEArKquoANPqGKLAi7LAEsPEuyeyM6ozs6KzyilywfoQUWljIEAAqhADmtX7qEAC8EADeEADaANIQNMQQAETxFADW0IQKgxAAPkNEjPCw+OgAajRIAO6DALp4AEaEhI0JEAC+ANx6buQQpEjoecS1pHg19Y2kLe1hsGMTCjwlHoSCiEkWyzWG02eAAZsV7ucrmAbsckBoSrUABT3R79F4aEbjSagu4PJ4EhZLFbrLYASguEHMwMU8L89zMhhMRk5lms7AAQg4kPxSs5rBE1F9wuI8mwID4aORhOhSZQEqRYaVGAlRCk0kUSmUwBVFABRWQUTDfDo0FB4cgUfGMxj9eiq14cJj7EVIk3YRQAOXofj8sH2jQtlGtrQ6PT6A1GSEwhFhECjVr26ctmB6O1mXtDfpRJFuKAosFh6DwwdD4cjOZtfXthb8YNdxHd6jwAE4AAzF1GNDF1LHlyvoDR2sHjqsaDtd0gMpmGTtF-u87lmcBQACqrlK8vC-VVFHh+EUxAAx0kLyFksktRQdV1ev0IBpP-nwjrEKgMAGWhQAAyoUhD4AAV2E6gLCqfwQMkfj9CoCH7LANDeF4EAUJM8HEPA3gYKQ+BgkIF4+jgehQCKOEUNUwEAIwMQAbD2eC2OC8Bdmg8A4XwWAcLAWQJghAwniK56KIw9C3EIsK+nIkCiQqvhCKQpA0CQECbEohCIqafRfIhIQisUAGVKUCEQAA5DINAAI4gncmCMIcfjWeZ6LaLo5jiWeyyKO8DTqAAkpJPzxu+wx-MSUwFoMVKQrS2xZocaKnGcm6mLEKlsBQ6DtGcGClMQGQIRQjk0DwLgQIwVAoCGvDULxmntgkqqJBAekcIQWTSoocrsCU+DoZoYA+HlBVtJcYBAA" rel="noopener noreferrer"&gt;Abrir este código no TypeScript Playground&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;É só abrir o link e ver o resultado logo do lado direito da tela. Se preferir, copie e cole o código acima e rode na sua própria IDE.&lt;/p&gt;

&lt;p&gt;De uma forma ou de outra, descomente a linha do &lt;code&gt;interface&lt;/code&gt; para ver o erro &lt;code&gt;TS1169&lt;/code&gt; de perto. Em seguida, experimente trocar a união de &lt;code&gt;Toggles&lt;/code&gt; por outras chaves, ou embrulhar &lt;code&gt;Entry[K]&lt;/code&gt; em algo diferente de &lt;code&gt;| null&lt;/code&gt; no &lt;code&gt;NullableEntry&lt;/code&gt;. É treinando essas variações que o &lt;code&gt;{ [K in ...]: ... }&lt;/code&gt; deixa de parecer sintaxe decorada e passa a ser uma ferramenta que você sabe montar do zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Mapped types resolvem um problema chato e comum: manter tipos paralelos em sincronia. Em vez de copiar um tipo e transformar campo por campo na mão, você descreve a transformação uma vez, &lt;code&gt;{ [K in keyof T]: ... }&lt;/code&gt;, e o compilador aplica ela a toda chave. Adicione um campo ao tipo de origem, e cada variação derivada dele se atualiza sozinha sem mais trabalho manual e com menos propensão a bugs.&lt;/p&gt;

&lt;p&gt;Depois de destrinchar o mecanismo, &lt;code&gt;{ [K in keyof Entry]: Entry[K] | null }&lt;/code&gt; se lê como uma frase: "para cada chave &lt;code&gt;K&lt;/code&gt; de &lt;code&gt;Entry&lt;/code&gt;, mantenha o tipo de valor original, mas também permita &lt;code&gt;null&lt;/code&gt;". E o ganho vai além do caso pontual: &lt;code&gt;Partial&lt;/code&gt;, &lt;code&gt;Required&lt;/code&gt;, &lt;code&gt;Readonly&lt;/code&gt; e &lt;code&gt;Record&lt;/code&gt; deixam de parecer mágica e passam a ser o que são de fato, mapped types comuns que o TypeScript já escreveu por você. Entender a mecânica por baixo deles é o que te permite ir além dos prontos e escrever a sua própria transformação quando nenhum utility type existente resolve.&lt;/p&gt;

&lt;p&gt;Se quiser revisitar todos os exemplos deste artigo juntos, num único arquivo, prontos para você testar sem precisar montar nada do zero, aqui está:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔗 &lt;a href="https://www.typescriptlang.org/play/?ssl=13&amp;amp;ssc=1&amp;amp;pln=13&amp;amp;pc=8#code/C4TwDgpgBAogdsATiKBeKBvKBLAJgLigGcls4BzAbigFsyBXYCIwuemgIwkSgF9KAUAID0wqAFpJQ0VACyAQzbyANgBooAY3k0wAeyh6eWnbsJbc8zdr1REESMDz7oSRUQBmuxDXm59cSxoAY90AOgFQSCgAOXplZXkOZQh4JBAFJWU0TAEoHAJiUgooAB8oNnjBPLo2JhZy9i4eMorlQX4hDV04EihcRHl3YEJY+MTk1OQM+hVsrDxWOLVaBjrCAE4ABj5BAS6e3WTQ5V1yAAp+weBQvHVLodCaxmYASmoZVqgt6TFJcR+oABrCAgXTuKDKABXUHYUF0HAAVhANMAoJFoNAwIhdLh6AAvKCWehwbAhPq6IjlXQ0Zh9eSUjQAC3kADdmOF0bAEMgANIgynoYGg8GTEDvMQQACO9GwLJU0EsACI8IrSlBFU86or1EQAM9QaXQLTKDRxXy6TrdXoQbkgPkgQii+0C9UqwT7a22+0ARkdXv52Q1q2Yit2HsOEGOpzONrS9vUsd5IO9bygMjwK1qzABHtRZDlyjwTpBfrjAfQit0wEZ3FDabEcDJXR02ASAL+AIAknBcBAAB4QXCEjQaZj1KFwtHYGx+KAFrxQcgzRAWWcQGgwnyaZlsjngaCd3AAFX32VFAG1lbhFQBdcWFRBkcgRU+yYNEE9RdAXoNZoi3+82E4bhLR6PNcAANRUegIEIQ9P2gCsIG9UM9itVFNWYKDlBgwg3z-BDsgAFgAJjDK0Iyjc48GwmD1EwohaIgVMZGQqBSPbKQRDEAApVl5AAZQ0R8wFRMB6GxHV1ygBChJE1F5DICxwlzIEQUDN00LAuFETmKBzyFG9CEVZDVQ6LSiEok5znhBEWLEeYCgAcmQpy+E4-4XyiI9TnIZIXSwc8eRwOB1QsRBAVkHEIFVMpFWbMB5BRCDsAgAB3W9CA4XQI0UHYPIBBQwEgIdOSIaTXB6TxvHkABzkJCEgRAukQOwrAsbdWWgXsuTSbjaEUJge30fRHBnI1fEsedEHCGQAHlbGYOJgHNKAAEvNynGw4F0FldHo+lNGpKBqq3JTsBIJ96AAW7ZLIetFPcolFABhXQwBQdBAuCsg1OFXrkCMgGQCCm98os1FExAN6PtLZAYc+zB8mM0z6PfDZtg6VSOCSwEfNFOHEahhH7zIJhmu0DhsAAQ7ZC76OYLdTvkUDLKOayY1tBGblwBMufekBHnfdQcY0PHdEehj7KgNiti+TYCq86BRgSJIUltPSgpCv6wWBoGLx5MGWiWcGPibakwFbSxxHycoyT0Hryp4Vp+tUmgQAJ4G9IWBp4jRv9CBIgB2cG3Y920AHVsGrFWmPqFXxnVtJvYKVp-eeepg9N34uJkABVLc2UQIgyR8TIZcJLFdD7bAfA62dDUnAAFeREEcFQAB4jwAPjRbrqb6aByAGWr5FmsQFoAfkJaVsHWycaBxbB3GwcwFx696NGwboVEICBkgMaLiG4SvCzXwfuX0Hr2H6nxisHNFT1nGkiEXqAkWj-RG-K0-V8sIkNzGG2l4HwygnrQBbm3bAKhRSax+qFIUutRQ3knoTUG2coALUge3ZQXde4BEcHtckMl9xyWnKidw8gCT9nkCtGkCAFS0EZpYLoF0x5KygNg6ByhRQACEZTKGAN2bIXDO6im7uRbSiVgBMkIKInhGsvqZgzoQIiABWHY9ZbYO2gCvLQPAerVRZtjARQi4AtxkYyORrccF8NMcIpRDFVEaP4Fol+b87BEGWuaAEb034UnJBdLaATgCQg3IEZhJ0QHyHULCaag9NpOzZAYbg7gIDR20LGCArtqQjThIwbEKl0IGGxGCaxUCYGKKgBwex5jaFMkkWzSMHNpFMiFn+EWtSLFtIYuoKuYJ2kZ2luo9iGj1FCCAA" rel="noopener noreferrer"&gt;Ver todos os exemplos juntos no TypeScript Playground&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Os exemplos estão organizados na mesma ordem em que apareceram no texto.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>mappedtypes</category>
    </item>
    <item>
      <title>Sistemas de Tipos: os três eixos que definem como uma linguagem se comporta</title>
      <dc:creator>Isaac Muniz</dc:creator>
      <pubDate>Sat, 02 May 2026 16:38:53 +0000</pubDate>
      <link>https://dev.to/imuniz/sistemas-de-tipos-os-tres-eixos-que-definem-como-uma-linguagem-se-comporta-1na6</link>
      <guid>https://dev.to/imuniz/sistemas-de-tipos-os-tres-eixos-que-definem-como-uma-linguagem-se-comporta-1na6</guid>
      <description>&lt;p&gt;Todo dado em um programa tem um tipo. Um número inteiro, um texto, um valor verdadeiro ou falso - cada um desses é um tipo diferente, e a linguagem precisa saber com qual está lidando para executar operações sobre ele corretamente.&lt;br&gt;
Mas o que acontece quando você tenta somar um número com um texto? Ou usar um objeto onde se espera outro? É aí que entram os sistemas de tipos: o conjunto de regras que cada linguagem define para lidar com essas situações. Diferentes linguagens fazem escolhas muito diferentes nesse sentido, e entender essas escolhas é essencial para qualquer desenvolvedor.&lt;/p&gt;

&lt;p&gt;Para entender essas diferenças, precisamos primeiro responder uma pergunta mais fundamental: o que é exatamente um tipo?&lt;/p&gt;
&lt;h2&gt;
  
  
  Mas afinal, o que é um tipo?
&lt;/h2&gt;

&lt;p&gt;Um tipo define duas coisas: quais valores são válidos e quais operações podem ser realizadas sobre eles. Quando você cria uma variável do tipo &lt;code&gt;number&lt;/code&gt;, a linguagem entende que você pode fazer contas com ela. Quando cria uma do tipo &lt;code&gt;string&lt;/code&gt;, a linguagem sabe que você pode concatenar, dividir em partes, converter para maiúsculas.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tipos Primitivos e Tipos Compostos
&lt;/h3&gt;

&lt;p&gt;Existem dois grandes grupos de tipos: os primitivos e os compostos.&lt;/p&gt;
&lt;h4&gt;
  
  
  Tipos Primitivos
&lt;/h4&gt;

&lt;p&gt;Tipos primitivos são os blocos de construção elementares. Toda linguagem tem algo parecido com isto:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// TypeScript&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;idade&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Isaac&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ativo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Python
&lt;/span&gt;&lt;span class="n"&gt;idade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;    &lt;span class="c1"&gt;# int
&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Isaac&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;    &lt;span class="c1"&gt;# str
&lt;/span&gt;&lt;span class="n"&gt;ativo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;    &lt;span class="c1"&gt;# bool
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Go&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;27&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Isaac"&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ativo&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;São valores simples, indivisíveis. Um número é um número. Uma string é uma sequência de caracteres. Um booleano é verdadeiro ou falso.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tipos compostos
&lt;/h4&gt;

&lt;p&gt;Tipos compostos são construídos a partir de outros tipos - sejam primitivos ou outros compostos. Eles agrupam dados relacionados em uma estrutura única. Aqui é onde as diferenças entre linguagens começam a aparecer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// TypeScript&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Pessoa&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;idade&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isaac&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Pessoa&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Isaac&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;idade&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Python
&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pessoa&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nome&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;idade&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;idade&lt;/span&gt;

&lt;span class="n"&gt;isaac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Pessoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Isaac&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Go&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Pessoa&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Nome&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;Idade&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;isaac&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Pessoa&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Nome&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Isaac"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Idade&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;27&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A ideia é a mesma em todas: agrupar dados relacionados sob um único tipo. Mas por que isso importa?&lt;/p&gt;

&lt;p&gt;Porque assim a linguagem consegue garantir certos comportamentos. Se você tem uma função que espera receber uma &lt;code&gt;Pessoa&lt;/code&gt;, a linguagem pode verificar que você está passando realmente uma &lt;code&gt;Pessoa&lt;/code&gt; - não uma string confundida por acaso. E é aqui que as linguagens começam a divergir: cada uma tem regras diferentes sobre o que é ou não permitido. Vamos começar pela diferença mais intuitiva.&lt;/p&gt;

&lt;h2&gt;
  
  
  Como diferentes linguagens tratam a tipagem
&lt;/h2&gt;

&lt;p&gt;Agora que sabemos o que é um tipo, podemos explorar como as linguagens diferem na forma de lidar com eles. Essa diferença aparece em situações concretas do dia a dia: o que acontece quando você passa um valor do tipo errado para uma função? Quando a linguagem detecta o problema? Ela avisa ou simplesmente segue em frente? As respostas variam bastante, e entendê-las ajuda a tomar decisões mais conscientes, tanto na escolha de uma linguagem quanto no uso dela. Vamos aos exemplos.&lt;/p&gt;

&lt;p&gt;Em JavaScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// JavaScript&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;   &lt;span class="c1"&gt;// == "53" - o número foi silenciosamente convertido para string&lt;/span&gt;
&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;   &lt;span class="c1"&gt;// == 2 - agora a string foi silenciosamente convertida para número&lt;/span&gt;
&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;   &lt;span class="c1"&gt;// "[object Object]" - resultado que não faz sentido&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O resultado muda dependendo do operador, sem nenhum aviso, sem nenhum erro. Por isso nos exemplos está escrito "silenciosamente". A linguagem fez &lt;strong&gt;coerções implícitas&lt;/strong&gt; - converteu os tipos automaticamente para tentar fazer a operação funcionar de qualquer jeito. Isso é &lt;strong&gt;tipagem fraca&lt;/strong&gt;: a linguagem aceita operações entre tipos incompatíveis sem reclamar.&lt;/p&gt;

&lt;p&gt;PHP tem um comportamento semelhante:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// PHP&lt;/span&gt;
&lt;span class="s2"&gt;"5"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// == 8 - string convertida para número automaticamente&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PHP moderno evoluiu bastante com o suporte a type hints.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;O que são type hints?&lt;/strong&gt;&lt;br&gt;
Type hints são anotações opcionais que você adiciona ao código para indicar explicitamente qual tipo de dado uma variável, parâmetro ou retorno de função deve ter. O nome é sugestivo: são "dicas de tipo". Dependendo da linguagem, elas podem ser verificadas pela própria linguagem, por ferramentas externas como editores e analisadores estáticos, ou por ambos. Em PHP moderno, ficaria assim:&lt;/p&gt;


&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// PHP&lt;/span&gt;
&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;dobrar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/blockquote&gt;

&lt;p&gt;PHP moderno, com type hints, melhorou bastante - mas ainda carrega o legado de ser permissivo com coerções. Outras linguagens fizeram a escolha oposta. Veja o que acontece em Python com a mesma tentativa de somar string e número:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Python
&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;  &lt;span class="c1"&gt;# TypeError: can only concatenate str (not "int") to str
&lt;/span&gt;
&lt;span class="c1"&gt;# Ou seja: "Erro de Tipagem: só é possível concatenar uma string (não um inteiro) à outra string"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A linguagem simplesmente se recusa. Se você quiser concatenar, precisa ser explícito: &lt;code&gt;"5" + str(3)&lt;/code&gt;. Isso é &lt;strong&gt;tipagem forte&lt;/strong&gt;: a linguagem exige que as operações façam sentido entre os tipos envolvidos.&lt;/p&gt;

&lt;p&gt;TypeScript e Go se comportam da mesma forma:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// TypeScript&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cinco&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Erro: Type 'string' is not assignable to type 'number'&lt;/span&gt;

&lt;span class="c1"&gt;// Traduzindo: "Erro: Tipo 'string' não é atribuível a tipo 'número'"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Go&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"cinco"&lt;/span&gt; &lt;span class="c"&gt;// cannot use "cinco" (type string) as type int&lt;/span&gt;

&lt;span class="c"&gt;// Traduzindo: "não é possível usar "cinco" (do tipo string) como tipo inteiro"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Resumindo:&lt;/strong&gt; forte/fraco mede a &lt;strong&gt;tolerância da linguagem à ambiguidade de tipos&lt;/strong&gt;. Linguagens fracas tentam resolver a situação sozinhas, linguagens fortes exigem que você resolva.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Type hints e verificação em cada linguagem
&lt;/h2&gt;

&lt;p&gt;Type hints existem em várias linguagens, mas como cada uma as usa na prática? As diferenças são grandes - vão desde linguagens que verificam tudo antes de executar até linguagens que tratam type hints como puros comentários decorativos.&lt;/p&gt;

&lt;p&gt;Antes de ver uma tabela comparativa, vale entender o que acontece em cada linguagem quando um erro de tipo ocorre num programa real, porque as consequências são muito diferentes dependendo de onde a verificação acontece.&lt;/p&gt;

&lt;p&gt;Nas linguagens que verificam tipos em compilação, como TypeScript, Go e Java, erros de tipo nunca chegam ao usuário. O compilador rejeita o código e o programa simplesmente não é gerado. O desenvolvedor precisa corrigir o problema antes de compilar e portanto antes de publicar qualquer coisa.&lt;/p&gt;

&lt;p&gt;Nas linguagens que verificam em runtime, como PHP, o erro aparece durante a execução. Se não for tratado pelo código, o servidor retorna uma tela de erro para o usuário. Mas o PHP faz isso de duas formas diferentes, dependendo da configuração do arquivo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Type hints em PHP, e modo padrão vs modo estrito
&lt;/h3&gt;

&lt;p&gt;No modo padrão, o PHP tenta ser prestativo: antes de reclamar de um tipo errado, ele tenta converter o valor para o tipo esperado. Se conseguir, segue em frente silenciosamente. Só lança um erro quando a conversão é realmente impossível:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// PHP&lt;/span&gt;
&lt;span class="nf"&gt;dobrar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"5"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// PHP converte "5" para 5 silenciosamente - sem erro&lt;/span&gt;
&lt;span class="nf"&gt;dobrar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"abc"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// TypeError - impossível converter&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Esse comportamento é conveniente, mas também perigoso - pode esconder bugs em vez de expô-los. Por isso o PHP oferece um modo mais rigoroso. Basta adicionar a linha &lt;code&gt;declare(strict_types=1);&lt;/code&gt; no topo do arquivo para que a linguagem passe a exigir que os tipos batam exatamente, sem nenhuma conversão automática:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// PHP&lt;/span&gt;
&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;dobrar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"5"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// TypeError - mesmo sendo conversível&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;

&lt;p&gt;Em JavaScript, o comportamento é o mais permissivo de todos: erros de tipo raramente interrompem o programa. A linguagem tenta resolver a situação por conta própria com coerções, e o que sobra vai para o console do navegador - invisível para o usuário, silencioso para o desenvolvedor desatento.&lt;/p&gt;

&lt;h3&gt;
  
  
  Type hints em Python
&lt;/h3&gt;

&lt;p&gt;Python fica num meio-termo curioso: a linguagem tem tipagem forte - não faz coerções - mas as type hints não causam nenhum erro por si só. Se um valor do tipo errado entrar numa função, Python não vai reclamar das anotações. Vai reclamar somente quando a operação em si falhar, como tentar multiplicar uma string por outra. Nesse caso, lança uma exceção que, se não tratada, retorna um erro 500 para o usuário.&lt;/p&gt;

&lt;p&gt;Para verificação antecipada em Python, existem ferramentas externas que leem as type hints e apontam inconsistências antes da execução. As mais usadas são &lt;strong&gt;mypy&lt;/strong&gt;, a mais tradicional da comunidade, e &lt;strong&gt;pyright&lt;/strong&gt;, criada pela Microsoft. Já o &lt;strong&gt;Pylance&lt;/strong&gt; é uma extensão do VS Code que usa o pyright por baixo dos panos para mostrar os erros diretamente no editor enquanto você digita.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSDoc em JavaScript
&lt;/h3&gt;

&lt;p&gt;JavaScript também tem uma solução para verificação antecipada sem abrir mão de ser JavaScript: o &lt;strong&gt;JSDoc&lt;/strong&gt; combinado com a diretiva &lt;code&gt;// @ts-check&lt;/code&gt;. JSDoc é um padrão de comentários estruturados que permite anotar tipos diretamente em arquivos &lt;code&gt;.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// JavaScript&lt;/span&gt;
&lt;span class="c1"&gt;// @ts-check&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * @param {number} n
 * @returns {number}
 */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;dobrar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;dobrar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cinco&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// o editor sublinha o erro&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A diretiva &lt;code&gt;// @ts-check&lt;/code&gt; no topo do arquivo instrui o VS Code a verificar o arquivo usando o mesmo mecanismo do TypeScript por baixo dos panos. Você continua escrevendo JavaScript puro, sem mudar a extensão do arquivo, sem compilar nada. Em execução, os comentários são ignorados e nenhuma verificação acontece - só o editor lê e interpreta as anotações.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tabela: Tipagem em diferentes linguagens
&lt;/h2&gt;

&lt;p&gt;Com isso em mente, a tabela abaixo resume como cada linguagem se comporta:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Linguagem&lt;/th&gt;
&lt;th&gt;Quando a verificação acontece&lt;/th&gt;
&lt;th&gt;Quem verifica&lt;/th&gt;
&lt;th&gt;O que acontece num programa rodando quando há erro de tipo&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;JavaScript&lt;/td&gt;
&lt;td&gt;Não acontece nativamente&lt;/td&gt;
&lt;td&gt;Ferramentas externas (VS Code com &lt;code&gt;// @ts-check&lt;/code&gt; e JSDoc)&lt;/td&gt;
&lt;td&gt;O programa continua rodando com resultado imprevisível; erros aparecem só no console do navegador&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHP (modo padrão)&lt;/td&gt;
&lt;td&gt;Em runtime&lt;/td&gt;
&lt;td&gt;A própria linguagem&lt;/td&gt;
&lt;td&gt;Converte o valor silenciosamente e segue em frente&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHP (modo estrito)&lt;/td&gt;
&lt;td&gt;Em runtime&lt;/td&gt;
&lt;td&gt;A própria linguagem&lt;/td&gt;
&lt;td&gt;Lança &lt;code&gt;TypeError&lt;/code&gt;; se não tratado, o usuário vê uma página de erro 500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Não acontece nativamente&lt;/td&gt;
&lt;td&gt;Ferramentas externas (mypy, pyright, Pylance)&lt;/td&gt;
&lt;td&gt;Lança exceção; se não tratada, o usuário vê uma página de erro 500&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;Em compilação&lt;/td&gt;
&lt;td&gt;O compilador &lt;code&gt;tsc&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Impossível: o código não compila e nunca chega ao usuário&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;Em compilação&lt;/td&gt;
&lt;td&gt;O compilador &lt;code&gt;go&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Impossível: o código não compila e nunca chega ao usuário&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;Em compilação&lt;/td&gt;
&lt;td&gt;O compilador &lt;code&gt;javac&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Impossível: o código não compila e nunca chega ao usuário&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Os três eixos dos sistemas de tipos
&lt;/h2&gt;

&lt;p&gt;Forte e fraca, como falamos acima, é apenas uma das formas de classificar o sistema de tipos de uma linguagem. Existem três eixos independentes, e confundir um com o outro é muito comum:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Eixo&lt;/th&gt;
&lt;th&gt;Pergunta que responde&lt;/th&gt;
&lt;th&gt;Resposta&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Forte / Fraca&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A linguagem aceita operações entre tipos incompatíveis?&lt;/td&gt;
&lt;td&gt;Não aceita: Forte / Aceita: Fraca&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Estática / Dinâmica&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Os tipos são verificados antes ou durante a execução?&lt;/td&gt;
&lt;td&gt;Antes: Estática / Durante: Dinâmica&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Nominal / Estrutural&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dois tipos são compatíveis pelo nome ou pela forma?&lt;/td&gt;
&lt;td&gt;Pelo nome: Nominal / Pela forma: Estrutural&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Já vimos o primeiro eixo em detalhes. Vamos relembrá-lo e explorar os outros dois.&lt;/p&gt;

&lt;h3&gt;
  
  
  Forte vs. Fraca: o quanto a linguagem tolera operações entre tipos incompatíveis?
&lt;/h3&gt;

&lt;p&gt;Linguagens com tipagem fraca, como JavaScript e PHP, fazem coerções implícitas para tentar fazer a operação funcionar. Linguagens com tipagem forte, como Python, TypeScript e Go, se recusam e exigem que o código seja explícito.&lt;/p&gt;

&lt;h3&gt;
  
  
  Estática vs. Dinâmica: quando os tipos são verificados?
&lt;/h3&gt;

&lt;p&gt;Linguagens como Go compilam o código antes de rodar: um programa chamado compilador lê o código inteiro, verifica os tipos e só então gera o executável. Se houver um erro de tipo, o programa nem começa a rodar. Isso é &lt;strong&gt;tipagem estática&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Linguagens como Python e JavaScript não têm essa etapa. O código é lido e executado linha a linha, e os tipos só são verificados quando aquela linha específica roda. Um erro de tipo numa função raramente chamada pode passar despercebido por muito tempo - até o dia em que essa função for executada em produção. Isso é &lt;strong&gt;tipagem dinâmica&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TypeScript é um caso especial:&lt;/strong&gt; ele compila, mas não gera código de máquina - gera JavaScript, que depois é interpretado. Mesmo assim, é durante a compilação que os tipos são verificados, por isso é considerado estaticamente tipado.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Uma consequência prática da tipagem dinâmica é que a mesma variável pode receber valores de tipos diferentes ao longo do código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Python
&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;        &lt;span class="c1"&gt;# x aponta para um inteiro
&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# x agora aponta para uma string - sem erro
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso funciona porque em Python o tipo pertence ao valor, não à variável. A variável &lt;code&gt;x&lt;/code&gt; é só um nome que aponta para um valor: primeiro apontava para &lt;code&gt;5&lt;/code&gt; (do tipo &lt;code&gt;int&lt;/code&gt;), depois passou a apontar para &lt;code&gt;"hello"&lt;/code&gt; (do tipo &lt;code&gt;str&lt;/code&gt;). Os valores em si continuam tendo seus tipos - o que mudou foi apenas para qual valor &lt;code&gt;x&lt;/code&gt; está apontando.&lt;/p&gt;

&lt;p&gt;Em linguagens com tipagem estática, como Go, é o oposto: o tipo pertence à variável. Quando você declara &lt;code&gt;var x int&lt;/code&gt;, está dizendo que &lt;code&gt;x&lt;/code&gt; é um recipiente que só aceita inteiros. Ele não pode passar a apontar para uma string, independentemente do que aconteça:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Go&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello"&lt;/span&gt; &lt;span class="c"&gt;// ❌ cannot use "hello" (type string) as type int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  A escolha entre tipagem estática vs. dinâmica
&lt;/h4&gt;

&lt;p&gt;A escolha entre estática e dinâmica envolve uma troca. Tipagem estática oferece segurança antecipada: erros são detectados antes de o programa rodar, o que é especialmente valioso em projetos grandes. Tipagem dinâmica oferece flexibilidade e agilidade: o código tende a ser mais enxuto e não exige declarações de tipo em todo lugar, o que pode acelerar o desenvolvimento em projetos menores ou exploratórios. Não há uma escolha universalmente certa - depende do contexto.&lt;/p&gt;

&lt;h3&gt;
  
  
  Nominal vs. Estrutural: o que torna dois tipos compatíveis?
&lt;/h3&gt;

&lt;p&gt;Esse eixo responde a uma pergunta mais sutil: para a linguagem aceitar que um tipo &lt;code&gt;B&lt;/code&gt; seja usado onde se espera um tipo &lt;code&gt;A&lt;/code&gt;, o que precisa ser verdade?&lt;/p&gt;

&lt;p&gt;Em linguagens com tipagem &lt;strong&gt;nominal&lt;/strong&gt;, o que importa é o nome declarado. Dois tipos são compatíveis somente se houver uma relação explícita entre eles. Java é um exemplo claro:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Java&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Au!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se você criar uma classe &lt;code&gt;Cat&lt;/code&gt; com exatamente os mesmos métodos mas sem declarar &lt;code&gt;implements Animal&lt;/code&gt;, o Java não vai aceitar um &lt;code&gt;Cat&lt;/code&gt; onde se espera um &lt;code&gt;Animal&lt;/code&gt; - mesmo que a estrutura seja idêntica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Java&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Miau!"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;Animal&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Cat&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ❌ Cat cannot be converted to Animal&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Em linguagens com tipagem &lt;strong&gt;estrutural&lt;/strong&gt;, o que importa é a forma - os métodos e propriedades que o tipo possui. Se a estrutura bate, a operação é aceita, independentemente do nome ou de qualquer declaração explícita. TypeScript funciona assim:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// TypeScript&lt;/span&gt;
&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Au!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Dog nunca declarou que implementa Animal,&lt;/span&gt;
&lt;span class="c1"&gt;// mas TypeScript aceita porque a estrutura é compatível&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Animal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ✅&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Isso tem um nome: &lt;strong&gt;duck typing estático&lt;/strong&gt;. A expressão vem de um ditado em inglês: &lt;em&gt;"If it walks like a duck and quacks like a duck, it's a duck"&lt;/em&gt; - "se anda como pato e grasna como pato, é um pato". A identidade de um tipo é definida pelo que ele faz, não pelo que ele se declara ser. O "estático" indica que essa verificação ainda acontece em tempo de compilação.&lt;/p&gt;

&lt;p&gt;Python também é estrutural, mas sem checagem antecipada - qualquer objeto que tenha os métodos certos é aceito, e a linguagem só descobre incompatibilidades em execução. Go mistura as duas abordagens: tipos concretos são nominais, mas interfaces são estruturais, o que significa que uma struct satisfaz uma interface automaticamente, sem precisar declará-la explicitamente.&lt;/p&gt;

&lt;h4&gt;
  
  
  A escolha entre tipagem nominal vs. estrutural
&lt;/h4&gt;

&lt;p&gt;Tipagem nominal exige mais cerimônia no código - você precisa declarar explicitamente as relações entre tipos - mas em troca oferece contratos mais claros e verificáveis. É mais fácil saber exatamente o que uma função aceita e o que ela rejeita. Tipagem estrutural é mais flexível e menos verbosa, mas exige mais atenção do desenvolvedor: dois tipos podem ser compatíveis por acidente, simplesmente por terem os mesmos métodos, mesmo que representem conceitos completamente diferentes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Onde cada linguagem se encaixa
&lt;/h2&gt;

&lt;p&gt;Com os três eixos em mente, fica mais fácil comparar as linguagens de forma objetiva. A tabela abaixo mostra como cada uma se posiciona nesses eixos de tipagem:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Linguagem&lt;/th&gt;
&lt;th&gt;Forte / Fraca&lt;/th&gt;
&lt;th&gt;Estática / Dinâmica&lt;/th&gt;
&lt;th&gt;Nominal / Estrutural&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Java&lt;/td&gt;
&lt;td&gt;Forte&lt;/td&gt;
&lt;td&gt;Estática&lt;/td&gt;
&lt;td&gt;Nominal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;C#&lt;/td&gt;
&lt;td&gt;Forte&lt;/td&gt;
&lt;td&gt;Estática&lt;/td&gt;
&lt;td&gt;Nominal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;Forte&lt;/td&gt;
&lt;td&gt;Estática&lt;/td&gt;
&lt;td&gt;Misto (nominal para tipos concretos, estrutural para interfaces)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TypeScript&lt;/td&gt;
&lt;td&gt;Forte&lt;/td&gt;
&lt;td&gt;Estática&lt;/td&gt;
&lt;td&gt;Estrutural&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Forte&lt;/td&gt;
&lt;td&gt;Dinâmica&lt;/td&gt;
&lt;td&gt;Estrutural&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ruby&lt;/td&gt;
&lt;td&gt;Forte&lt;/td&gt;
&lt;td&gt;Dinâmica&lt;/td&gt;
&lt;td&gt;Estrutural&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHP&lt;/td&gt;
&lt;td&gt;Fraca&lt;/td&gt;
&lt;td&gt;Dinâmica&lt;/td&gt;
&lt;td&gt;Ambíguo (nominal com classes e interfaces, mas historicamente permissivo)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JavaScript&lt;/td&gt;
&lt;td&gt;Fraca&lt;/td&gt;
&lt;td&gt;Dinâmica&lt;/td&gt;
&lt;td&gt;Estrutural&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Nenhuma combinação é universalmente melhor. Cada uma reflete escolhas de design que priorizam coisas diferentes: segurança, flexibilidade, produtividade ou clareza de contrato.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do sistema de tipos mais rígido para o mais permissivo
&lt;/h3&gt;

&lt;p&gt;Considerando os três eixos juntos - onde forte é mais rígido que fraco, estática mais rígida que dinâmica, e nominal mais rígida que estrutural - é possível ordenar as linguagens do sistema de tipos mais restritivo para o mais permissivo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Java, C#&lt;/strong&gt; - forte + estática + nominal: o nível mais alto de restrição, com verificação antecipada e contratos explícitos obrigatórios&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go&lt;/strong&gt; - forte + estática + nominal/estrutural: tão rígido quanto Java e C# na verificação antecipada, mas um pouco mais flexível nas interfaces&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript&lt;/strong&gt; - forte + estática + estrutural: verificação antecipada sem exigir declarações explícitas de conformidade&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python, Ruby&lt;/strong&gt; - forte + dinâmica + estrutural: sem coerções, mas erros só aparecem em execução&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PHP&lt;/strong&gt; - fraca + dinâmica + ambíguo: permissivo por padrão, com rigor opcional via &lt;code&gt;strict_types&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript&lt;/strong&gt; - fraca + dinâmica + estrutural: o sistema de tipos mais permissivo da lista&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Vale lembrar que essa ordenação é uma simplificação. Na prática, a rigidez de um sistema de tipos depende também de como o desenvolvedor usa a linguagem - PHP com &lt;code&gt;strict_types&lt;/code&gt; e mypy no Python, por exemplo, podem se comportar de forma bem mais rígida do que a posição deles na lista sugere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusão
&lt;/h2&gt;

&lt;p&gt;Tipos são um daqueles assuntos que parecem simples até você começar a comparar como linguagens diferentes os tratam. Um mesmo erro pode travar o programa antes de rodar, explodir em produção, ou passar completamente despercebido, dependendo das escolhas que a linguagem faz. Conhecer essas diferenças muda a forma como você lê erros, escolhe ferramentas e escreve código.&lt;/p&gt;

</description>
      <category>tipagem</category>
      <category>typescript</category>
      <category>go</category>
      <category>python</category>
    </item>
  </channel>
</rss>
