

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Siga as TypeScript melhores práticas
<a name="typescript-best-practices"></a>

TypeScript é uma linguagem que amplia os recursos do JavaScript. É uma linguagem fortemente digitada e orientada a objetos. Você pode usar TypeScript para especificar os tipos de dados que estão sendo transmitidos em seu código e tem a capacidade de relatar erros quando os tipos não coincidem. Esta seção fornece uma visão geral das TypeScript melhores práticas.

## Descreva seus dados
<a name="describe-data"></a>

Você pode usar TypeScript para descrever a forma dos objetos e funções em seu código. Usar o tipo `any` é equivalente a optar por não verificar o tipo de uma variável. Recomendamos evitar usar `any`em seu código. Aqui está um exemplo.

```
type Result = "success" | "failure"
function verifyResult(result: Result) {
    if (result === "success") {
        console.log("Passed");
    } else {
        console.log("Failed")
    }
}
```

## Use enumerações
<a name="use-enums"></a>

É possível usar enumerações para definir um conjunto de constantes nomeadas e definir padrões que podem ser reutilizados em sua base de código. Recomendamos exportar suas enumerações uma vez em nível global e depois permitir que outras classes importem e usem as enumerações. Suponha que você queira criar um conjunto de ações possíveis para capturar os eventos em sua base de código. TypeScript fornece enumerações numéricas e baseadas em seqüências de caracteres. O exemplo a seguir usa uma enumeração.

```
enum EventType {
    Create,
    Delete,
    Update
}

class InfraEvent {
    constructor(event: EventType) {
        if (event === EventType.Create) {
            // Call for other function
            console.log(`Event Captured :${event}`);
        }
    }
}

let eventSource: EventType = EventType.Create;
const eventExample = new InfraEvent(eventSource)
```

## Use interfaces do
<a name="use-interfaces"></a>

Uma interface é um contrato para a classe. Se você criar um contrato, os usuários deverão cumpri-lo. No exemplo a seguir, uma interface é usada para padronizar `props` e garantir que os chamadores forneçam o parâmetro esperado ao usar essa classe.

```
import { Stack, App } from "aws-cdk-lib";
import { Construct } from "constructs";

interface BucketProps {
    name: string;
    region: string;
    encryption: boolean;

}

class S3Bucket extends Stack {
    constructor(scope: Construct, props: BucketProps) {
        super(scope);
        console.log(props.name);

    }
}
const app = App();
const myS3Bucket = new S3Bucket(app, {
    name: "amzn-s3-demo-bucket",
    region: "us-east-1",
    encryption: false
})
```

Algumas propriedades só podem ser modificadas quando um objeto é criado pela primeira vez. É possível especificar isso colocando `readonly` antes do nome da propriedade, conforme mostrado no exemplo a seguir.

```
interface Position {
    readonly latitude: number;
    readonly longitute: number;
}
```

## Estenda interfaces
<a name="extend-interfaces"></a>

A extensão de interfaces reduz a duplicação, pois não é necessário copiar as propriedades entre as interfaces. Além disso, o leitor do seu código pode entender facilmente os relacionamentos em sua aplicação.

```
 interface BaseInterface{
    name: string;
  }
  interface EncryptedVolume extends BaseInterface{
      keyName: string;
  }
  interface UnencryptedVolume extends BaseInterface {
      tags: string[];
  }
```

## Evite interfaces vazias
<a name="empty-interfaces"></a>

Recomendamos evitar interfaces vazias devido aos riscos potenciais criados por elas. No exemplo a seguir, há uma interface vazia chamada`BucketProps`. Os objetos `myS3Bucket1` e `myS3Bucket2` são ambos válidos, mas seguem padrões diferentes porque a interface não impõe nenhum contrato. O código a seguir compilará e imprimirá as propriedades, mas isso introduz inconsistências na aplicação.

```
interface BucketProps {}

class S3Bucket implements BucketProps {
    constructor(props: BucketProps){
        console.log(props);
    }
}

const myS3Bucket1 = new S3Bucket({
    name: "amzn-s3-demo-bucket",
    region: "us-east-1",
    encryption: false,
});

const myS3Bucket2 = new S3Bucket({
    name: "amzn-s3-demo-bucket",
});
```

## Use fábricas
<a name="use-factories"></a>

Em um padrão Abstract Factory, uma interface é responsável por criar uma fábrica de objetos relacionados sem especificar explicitamente suas classes. Por exemplo, você pode criar uma fábrica do Lambda para criar funções do Lambda. Em vez de criar uma nova função Lambda em sua construção, você está delegando o processo de criação à fábrica. Para obter mais informações sobre esse padrão de design, consulte [Abstract Factory TypeScript na documentação](https://refactoring.guru/design-patterns/abstract-factory/typescript/example) do Refactoring.Guru.

## Use desestruturação em propriedades
<a name="destructuring-props"></a>

A desestruturação, introduzida em ECMAScript 6 (ES6), é um JavaScript recurso que permite extrair vários dados de uma matriz ou objeto e atribuí-los às suas próprias variáveis.

```
const object = {
    objname: "obj",
    scope: "this",
};

const oName = object.objname;
const oScop = object.scope;

const { objname, scope } = object;
```

## Defina convenções de nomenclatura padrão
<a name="naming-conventions"></a>

A aplicação de uma convenção de nomenclatura mantém a base de código consistente e reduz a sobrecarga representada por pensar em como nomear uma variável. Recomendamos o seguinte:
+ Use camelCase para nomes de variáveis e funções.
+ Use UPPER\$1CASE para constantes globais para indicar claramente valores imutáveis de tempo de compilação.
+ Use PascalCase para nomes de classes e nomes de interface.
+ Use camelCase para membros da interface.
+ Use PascalCase para nomes de tipos e nomes de enumeração.
+ Nomeie arquivos com camelCase (por exemplo, `ebsVolumes.tsx` ou `storage.ts`)

Veja a seguir exemplos dessas convenções de nomenclatura recomendadas:

```
// Variables and functions
const userName = 'john';
function getUserData() { }

// Global constants
const MAX_RETRY_ATTEMPTS = 3;
const API_BASE_URL = 'https://api.example.com';

// Classes and interfaces
class DatabaseConnection { }
interface UserProfile { }

// Types and enums
type ResponseStatus = 'success' | 'error';
enum HttpStatusCode { }
```

## Não use a palavra-chave var
<a name="var-keyword"></a>

A `let` instrução é usada para declarar uma variável local em TypeScript. É semelhante à `var` palavra-chave, mas tem algumas restrições no escopo em comparação com a `var` palavra-chave. Uma variável declarada em um bloco com `let` só está disponível para uso dentro desse bloco. A `var` palavra-chave não pode ter escopo de bloco, o que significa que ela pode ser acessada fora de um bloco específico (representado por`{}`), mas não fora da função em que está definida. Você pode redeclarar e atualizar `var` variáveis. É uma prática recomendada evitar o uso da `var` palavra-chave.

## Considere usar ESLint e Prettier
<a name="eslint-prettier"></a>

ESLint analisa estaticamente seu código para encontrar problemas rapidamente. Você pode usar ESLint para criar uma série de afirmações (chamadas *regras de lint*) que definem a aparência ou o comportamento do seu código. ESLint também tem sugestões de correção automática para ajudar você a melhorar seu código. Finalmente, você pode usar ESLint para carregar regras de lint de plug-ins compartilhados.

O Prettier é um formatador de código conhecido compatível com toda uma variedade de linguagens de programação. O Prettier pode ser usado para definir seu estilo de código a fim de evitar sua formatação manual. Após a instalação, você pode atualizar seu arquivo `package.json` e executar os comandos `npm run format` e `npm run lint`.

O exemplo a seguir mostra como habilitar o ESLint formatador Prettier para seu AWS CDK projeto.

```
"scripts": {
    "build": "tsc",
    "watch": "tsc -w",
    "test": "jest",
    "cdk": "cdk",
    "lint": "eslint --ext .js,.ts .",
    "format": "prettier --ignore-path .gitignore --write '**/*.+(js|ts|json)'"
}
```

## Use modificadores de acesso
<a name="access-modifiers"></a>

O modificador privado em TypeScript limita a visibilidade somente para a mesma classe. Ao adicionar o modificador privado a uma propriedade ou método, é possível acessar essa propriedade ou método dentro da mesma classe.

O modificador público permite que propriedades e métodos de classe sejam acessíveis de todos os locais. Se você não especificar nenhum modificador de acesso para propriedades e métodos, eles usarão o modificador público por padrão.

O modificador protegido permite que propriedades e métodos de uma classe sejam acessíveis dentro da mesma classe e dentro de subclasses. Use o modificador protegido quando você espera criar subclasses em seu AWS CDK aplicativo.

## Use tipos de utilitários
<a name="utility-types"></a>

Os *tipos de utilitários* em TypeScript são funções de tipo predefinidas que realizam transformações e operações em tipos existentes. Isso ajuda você a criar novos tipos com base nos tipos existentes. Por exemplo, você pode alterar ou extrair propriedades, tornar as propriedades opcionais ou obrigatórias ou criar versões imutáveis de tipos. Ao usar tipos de utilitários, você pode definir tipos mais precisos e capturar possíveis erros em tempo de compilação.

### Parcial <Type>
<a name="partial-type"></a>

`Partial`marca todos os membros de um tipo de entrada `Type` como opcionais. Esse utilitário retorna um tipo que representa todos os subconjuntos de um determinado tipo. Veja a seguir um exemplo de `Partial`.

```
interface Dog {
  name: string;
  age: number;
  breed: string;
  weight: number;
}

let partialDog: Partial<Dog> = {};
```

### Obrigatório <Type>
<a name="required-type"></a>

`Required`faz o oposto de`Partial`. Isso torna todos os membros de um tipo de entrada `Type` não opcionais (em outras palavras, obrigatórios). Veja a seguir um exemplo de `Required`.

```
interface Dog {
  name: string;
  age: number;
  breed: string;
  weight?: number;
}

let dog: Required<Dog> = { 
  name: "scruffy",
  age: 5,
  breed: "labrador",
  weight: 55 // "Required" forces weight to be defined
};
```