+ É possível suportar múltiplos tipos de indexadores...
+ É possível suportar múltiplos tipos de indexadores. Note que ao usar tanto indexadores `number` quanto `string`, o tipo retornado de um indexador numérico deve ser um subtipo do tipo retornado do indexador de string. Isso acontece porque, ao indexar com um number, o JavaScript na verdade vai convertê-lo para uma string antes de indexar em um objeto. Isso significa que indexar com 100 (um number) é a mesma coisa que indexar com "100" (uma string), então os dois precisam ser consistentes.
+
+```ts twoslash
+// @errors: 2413
+// @strictPropertyInitialization: false
+interface Animal {
+ name: string;
+}
+
+interface Dog extends Animal {
+ breed: string;
+}
+
+// Erro: indexar com uma string numérica pode te dar um tipo de Animal completamente separado!
+interface NotOkay {
+ [x: number]: Animal;
+ [x: string]: Dog;
+}
+```
+
+
+
+Embora assinaturas de índice de string sejam uma forma poderosa de descrever o padrão de "dicionário", elas também forçam que todas as propriedades correspondam ao seu tipo de retorno.
+Isso acontece porque um índice de string declara que `obj.property` também está disponível como `obj["property"]`.
+No exemplo a seguir, o tipo de `name` não corresponde ao tipo do índice de string, e o verificador de tipos dá um erro:
+
+```ts twoslash
+// @errors: 2411
+// @errors: 2411
+interface NumberDictionary {
+ [index: string]: number;
+
+ length: number; // ok
+ name: string;
+}
+```
+
+No entanto, propriedades de tipos diferentes são aceitáveis se a assinatura de índice for uma união dos tipos das propriedades:
+
+```ts twoslash
+interface NumberOrStringDictionary {
+ [index: string]: number | string;
+ length: number; // ok, length é um number
+ name: string; // ok, name é uma string
+}
+```
+
+Por fim, você pode tornar assinaturas de índice `readonly` para prevenir atribuição aos seus índices:
+
+```ts twoslash
+declare function getReadOnlyStringArray(): ReadonlyStringArray;
+// ---cut---
+// @errors: 2542
+interface ReadonlyStringArray {
+ readonly [index: number]: string;
+}
+
+let myArray: ReadonlyStringArray = getReadOnlyStringArray();
+myArray[2] = "Mallory";
+```
+
+Você não pode definir `myArray[2]` porque a assinatura de índice é `readonly`.
+
+## Verificações de Propriedades Excedentes
+
+Onde e como um objeto recebe um tipo pode fazer diferença no sistema de tipos.
+Um dos exemplos principais disso é a verificação de propriedades excedentes (excess property checking), que valida o objeto de forma mais completa quando ele é criado e atribuído a um tipo de objeto durante a criação.
+
+```ts twoslash
+// @errors: 2345 2739
+interface SquareConfig {
+ color?: string;
+ width?: number;
+}
+
+function createSquare(config: SquareConfig): { color: string; area: number } {
+ return {
+ color: config.color || "red",
+ area: config.width ? config.width * config.width : 20,
+ };
+}
+
+let mySquare = createSquare({ colour: "red", width: 100 });
+```
+
+Note que o argumento dado para `createSquare` está escrito como _`colour`_ em vez de `color`.
+Em JavaScript puro, esse tipo de coisa falha silenciosamente.
+
+Você poderia argumentar que este programa está corretamente tipado, já que as propriedades `width` são compatíveis, não há propriedade `color` presente, e a propriedade extra `colour` é insignificante.
+
+No entanto, o TypeScript assume a posição de que provavelmente há um bug neste código.
+Literais de objeto recebem tratamento especial e passam por _verificação de propriedades excedentes_ ao serem atribuídos a outras variáveis, ou passados como argumentos.
+Se um literal de objeto tem qualquer propriedade que o "tipo alvo" não tem, você vai receber um erro:
+
+```ts twoslash
+// @errors: 2345 2739
+interface SquareConfig {
+ color?: string;
+ width?: number;
+}
+
+function createSquare(config: SquareConfig): { color: string; area: number } {
+ return {
+ color: config.color || "red",
+ area: config.width ? config.width * config.width : 20,
+ };
+}
+// ---cut---
+let mySquare = createSquare({ colour: "red", width: 100 });
+```
+
+Contornar essas verificações é, na verdade, bem simples.
+O método mais fácil é apenas usar uma asserção de tipo:
+
+```ts twoslash
+// @errors: 2345 2739
+interface SquareConfig {
+ color?: string;
+ width?: number;
+}
+
+function createSquare(config: SquareConfig): { color: string; area: number } {
+ return {
+ color: config.color || "red",
+ area: config.width ? config.width * config.width : 20,
+ };
+}
+// ---cut---
+let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);
+```
+
+No entanto, uma abordagem melhor pode ser adicionar uma assinatura de índice de string se você tem certeza de que o objeto pode ter algumas propriedades extras que são usadas de alguma forma especial.
+Se `SquareConfig` pode ter propriedades `color` e `width` com os tipos acima, mas também poderia ter qualquer número de outras propriedades, então poderíamos defini-lo assim:
+
+```ts twoslash
+interface SquareConfig {
+ color?: string;
+ width?: number;
+ [propName: string]: unknown;
+}
+```
+
+Aqui estamos dizendo que `SquareConfig` pode ter qualquer número de propriedades e, contanto que não sejam `color` ou `width`, seus tipos não importam.
+
+Uma última forma de contornar essas verificações, que pode ser um pouco surpreendente, é atribuir o objeto a outra variável:
+Como atribuir `squareOptions` não vai passar por verificações de propriedades excedentes, o compilador não vai te dar um erro:
+
+```ts twoslash
+interface SquareConfig {
+ color?: string;
+ width?: number;
+}
+
+function createSquare(config: SquareConfig): { color: string; area: number } {
+ return {
+ color: config.color || "red",
+ area: config.width ? config.width * config.width : 20,
+ };
+}
+// ---cut---
+let squareOptions = { colour: "red", width: 100 };
+let mySquare = createSquare(squareOptions);
+```
+
+A solução acima vai funcionar contanto que você tenha uma propriedade em comum entre `squareOptions` e `SquareConfig`.
+Neste exemplo, foi a propriedade `width`. No entanto, ela vai falhar se a variável não tiver nenhuma propriedade de objeto em comum. Por exemplo:
+
+```ts twoslash
+// @errors: 2559
+interface SquareConfig {
+ color?: string;
+ width?: number;
+}
+
+function createSquare(config: SquareConfig): { color: string; area: number } {
+ return {
+ color: config.color || "red",
+ area: config.width ? config.width * config.width : 20,
+ };
+}
+// ---cut---
+let squareOptions = { colour: "red" };
+let mySquare = createSquare(squareOptions);
+```
+
+Tenha em mente que, para código simples como o acima, você provavelmente não deveria tentar "contornar" essas verificações.
+Para literais de objeto mais complexos que têm métodos e mantêm estado, você pode precisar ter essas técnicas em mente, mas a maioria dos erros de propriedade excedente são, na verdade, bugs.
+
+Isso significa que se você está esbarrando em problemas de verificação de propriedades excedentes para algo como "sacos de opções" (option bags), pode precisar revisar algumas de suas declarações de tipo.
+Neste caso, se está tudo bem passar um objeto com uma propriedade `color` ou `colour` para `createSquare`, você deveria corrigir a definição de `SquareConfig` para refletir isso.
+
+## Estendendo Tipos
+
+É bem comum ter tipos que podem ser versões mais específicas de outros tipos.
+Por exemplo, poderíamos ter um tipo `BasicAddress` que descreve os campos necessários para enviar cartas e pacotes nos EUA.
+
+```ts twoslash
+interface BasicAddress {
+ name?: string;
+ street: string;
+ city: string;
+ country: string;
+ postalCode: string;
+}
+```
+
+Em algumas situações isso é suficiente, mas endereços muitas vezes têm um número de unidade associado a eles se o prédio em um endereço tem múltiplas unidades.
+Podemos então descrever um `AddressWithUnit`.
+
+
+```ts twoslash
+interface AddressWithUnit {
+ name?: string;
+ unit: string;
+//^^^^^^^^^^^^^
+ street: string;
+ city: string;
+ country: string;
+ postalCode: string;
+}
+```
+
+Isso resolve o problema, mas a desvantagem aqui é que tivemos que repetir todos os outros campos de `BasicAddress` quando nossas mudanças eram puramente aditivas.
+Em vez disso, podemos estender o tipo `BasicAddress` original e apenas adicionar os novos campos que são únicos de `AddressWithUnit`.
+
+```ts twoslash
+interface BasicAddress {
+ name?: string;
+ street: string;
+ city: string;
+ country: string;
+ postalCode: string;
+}
+
+interface AddressWithUnit extends BasicAddress {
+ unit: string;
+}
+```
+
+A palavra-chave `extends` em uma `interface` nos permite efetivamente copiar membros de outros tipos nomeados e adicionar quaisquer novos membros que quisermos.
+Isso pode ser útil para reduzir a quantidade de boilerplate de declaração de tipo que temos que escrever, e para sinalizar a intenção de que várias declarações diferentes da mesma propriedade podem estar relacionadas.
+Por exemplo, `AddressWithUnit` não precisou repetir a propriedade `street` e, como `street` se origina de `BasicAddress`, quem lê vai saber que esses dois tipos estão relacionados de alguma forma.
+
+`interface`s também podem estender de múltiplos tipos.
+
+```ts twoslash
+interface Colorful {
+ color: string;
+}
+
+interface Circle {
+ radius: number;
+}
+
+interface ColorfulCircle extends Colorful, Circle {}
+
+const cc: ColorfulCircle = {
+ color: "red",
+ radius: 42,
+};
+```
+
+## Tipos de Interseção
+
+`interface`s nos permitiram construir novos tipos a partir de outros tipos estendendo-os.
+O TypeScript fornece outra construção chamada _tipos de interseção_ (intersection types) que é usada principalmente para combinar tipos de objeto existentes.
+
+Um tipo de interseção é definido usando o operador `&`.
+
+```ts twoslash
+interface Colorful {
+ color: string;
+}
+interface Circle {
+ radius: number;
+}
+
+type ColorfulCircle = Colorful & Circle;
+```
+
+Aqui, fizemos a interseção de `Colorful` e `Circle` para produzir um novo tipo que tem todos os membros de `Colorful` _e_ `Circle`.
+
+```ts twoslash
+// @errors: 2345
+interface Colorful {
+ color: string;
+}
+interface Circle {
+ radius: number;
+}
+// ---cut---
+function draw(circle: Colorful & Circle) {
+ console.log(`Color was ${circle.color}`);
+ console.log(`Radius was ${circle.radius}`);
+}
+
+// ok
+draw({ color: "blue", radius: 42 });
+
+// opa
+draw({ color: "red", raidus: 42 });
+```
+
+## Extensão de Interface vs. Interseção
+
+Acabamos de ver duas formas de combinar tipos que são parecidas, mas são, na verdade, sutilmente diferentes.
+Com interfaces, podíamos usar uma cláusula `extends` para estender de outros tipos, e conseguimos fazer algo similar com interseções e nomear o resultado com um alias de tipo.
+A principal diferença entre as duas é como conflitos são tratados, e essa diferença é tipicamente um dos principais motivos pelos quais você escolheria uma em vez da outra entre uma interface e um alias de tipo de um tipo de interseção.
+
+Se interfaces forem definidas com o mesmo nome, o TypeScript vai tentar fundi-las se as propriedades forem compatíveis. Se as propriedades não forem compatíveis (ou seja, têm o mesmo nome de propriedade mas tipos diferentes), o TypeScript vai levantar um erro.
+
+No caso de tipos de interseção, propriedades com tipos diferentes serão fundidas automaticamente. Quando o tipo for usado depois, o TypeScript vai esperar que a propriedade satisfaça ambos os tipos simultaneamente, o que pode produzir resultados inesperados.
+
+Por exemplo, o código a seguir vai lançar um erro porque as propriedades são incompatíveis:
+
+```ts
+interface Person {
+ name: string;
+}
+
+interface Person {
+ name: number;
+}
+```
+
+Em contraste, o código a seguir vai compilar, mas resulta em um tipo `never`:
+
+```ts twoslash
+interface Person1 {
+ name: string;
+}
+
+interface Person2 {
+ name: number;
+}
+
+type Staff = Person1 & Person2
+
+declare const staffer: Staff;
+staffer.name;
+// ^?
+```
+Neste caso, `Staff` exigiria que a propriedade `name` fosse tanto uma string quanto um number, o que resulta em a propriedade ser do tipo `never`.
+
+## Tipos de Objeto Genéricos
+
+Vamos imaginar um tipo `Box` que pode conter qualquer valor — `string`s, `number`s, `Giraffe`s, o que for.
+
+```ts twoslash
+interface Box {
+ contents: any;
+}
+```
+
+Por enquanto, a propriedade `contents` é tipada como `any`, o que funciona, mas pode levar a acidentes mais adiante.
+
+Em vez disso, poderíamos usar `unknown`, mas isso significaria que, nos casos em que já sabemos o tipo de `contents`, precisaríamos fazer verificações preventivas, ou usar asserções de tipo propensas a erros.
+
+```ts twoslash
+interface Box {
+ contents: unknown;
+}
+
+let x: Box = {
+ contents: "hello world",
+};
+
+// poderíamos verificar 'x.contents'
+if (typeof x.contents === "string") {
+ console.log(x.contents.toLowerCase());
+}
+
+// ou poderíamos usar uma asserção de tipo
+console.log((x.contents as string).toLowerCase());
+```
+
+Uma abordagem segura quanto a tipos seria, em vez disso, esboçar diferentes tipos de `Box` para cada tipo de `contents`.
+
+```ts twoslash
+// @errors: 2322
+interface NumberBox {
+ contents: number;
+}
+
+interface StringBox {
+ contents: string;
+}
+
+interface BooleanBox {
+ contents: boolean;
+}
+```
+
+Mas isso significa que vamos ter que criar diferentes funções, ou sobrecargas de funções, para operar sobre esses tipos.
+
+```ts twoslash
+interface NumberBox {
+ contents: number;
+}
+
+interface StringBox {
+ contents: string;
+}
+
+interface BooleanBox {
+ contents: boolean;
+}
+// ---cut---
+function setContents(box: StringBox, newContents: string): void;
+function setContents(box: NumberBox, newContents: number): void;
+function setContents(box: BooleanBox, newContents: boolean): void;
+function setContents(box: { contents: any }, newContents: any) {
+ box.contents = newContents;
+}
+```
+
+Isso é muito boilerplate. Além disso, podemos precisar mais tarde introduzir novos tipos e sobrecargas.
+Isso é frustrante, já que nossos tipos de box e sobrecargas são todos efetivamente os mesmos.
+
+Em vez disso, podemos fazer um tipo `Box` _genérico_ que declara um _parâmetro de tipo_.
+
+```ts twoslash
+interface Box