Builder de tipagem dinâmica com fluent api no typescript
Tags: typescript, fluentapi, node
Published: 2024-06-29 15:35:37

Nesse pequeno post iremos ver uma feature interessante do typescript que não vejo muitas pessoas comentando. Iremos aprender a utilizar a criação de uma tipagem dinâmica com o padrão de fluent api. 

Começaremos rapidamente definindo alguns componentes para trabalhar em cima deles. A ideia aqui é construirmos casas dinamicamente. Existem casa que possuem piscina, outras não. Iremos ver como definir sua casa de acordo com o objeto que está sendo construído!

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/16ceys5ifd1idwh7soak.png)

Começando com a fluent api, caso não esteja familiarizado com o padrão, trata-se de retornar a classe no retorno da função, para que seja possível encadear chamadas de funções. Abaixo um exemplo de utilização similar ao que faremos: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zf04wefh3i2a7oa30my5.png)

Agora que já estamos um pouco mais familiarizados com o padrão, vamos implementar de forma que a tipagem do nosso objeto seja atualizada dinamicamente. O objetivo é ter uma função `construir` que irá retornar a casa com a tipagem correta de nossa casa. 

Pra começar, primeiro precisamos de criar o tipo `Casa`, que será definido pela extensão das variáveis existentes em CasaProps. A definição ficará da seguinte forma: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/we2bsucez4pkgjp8u7n2.png)

Caso não esteja familiarizado com a tipagem, a explicação do que fizemos é a seguinte: 

a `Casa` receberá um parametro `T`, onde `T` será derivado das variáveis ("chaves") presentes em `CasaProps` (`T extends keyof CasaProps`). Então, para cada K ("chave") presente em T iremos adicioná-la a definição da casa, sendo que associaremos o valor de K ("chave") com o valor de CasaProps[K] (esse é o valor da mesma chave só que na tipagem CasaProps). 

Ainda confuso? Vamos ver o que isso representa no código, para assimilar melhor a ideia! 

Agora, quando criamos uma `Casa` teremos que associar a ela uma das propriedades presentes em `CasaProps`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x7t745bhipny2nfmdo5z.png)


Ao associarmos uma tipagem de `Casa<"quartos">` a uma variável, teremos uma casa com o atributo com quartos, que o valor terá a tipagem de `Quartos` que definimos em `CasaProps`. A mesma coisa acontece se fizermos uma casa com piscina, seremos forçados a incluir uma piscina dentro da casa

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dswoaj68ycsu5ims8qsu.png)

Agora, a virada da chave acontece se dissermos que essa casa possui quartos e banheiros, fazemos isso indicando as duas variáveis com um `|`. `Casa<"quartos" | "banheiros">` irá nos dizer que a casa terá os dois atributos existindo dentro dela! Além disso, caso não haja algum dos atributos seremos notificados com um erro explicito dizendo quais são os atributos que estão faltando:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e83sah382pb4150ex6tf.png)

Agora que dominamos o conceito da tipagem dinâmica, vamos avançar para o builder. Iremos criar uma classe `CasaBuilder`, que receberá um `T` que estende as chaves de `CasaProps` (`CasaBuilder<T extends keyof CasaProps = never>` - para que em um primeiro momento não exista nenhuma chave associada ao builder setamos primeiramente como never). 

Para a nossa fluent api, iremos ter um objeto privado `_casa` que receberá a configuração. Para cada um dos atributos teremos uma função específica de criação, para setar cada campo. No entanto, iremos atualizar dinamicamente nossa tipagem, retornando a tipagem `T | "variavel"` para cada variável que setarmos (exemplo: `T | "quartos"`>. Fazendo isso, iremos atualizar a nossa tipagem com um novo atributo. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iiqdozj6pkg56vglhikx.png)

Por fim, teremos uma função `construir()` que retornará a nossa casa com a tipagem atual. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kvy7thf80o5xgib8fpil.png)

Nossa classe ficou da seguinte forma: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cxph1wwoqcso1b0cwow6.png)

Agora, é possível criar de forma dinâmica nossa casa. Para criar uma casa apenas com piscina podemos facilmente criar adicionando a piscina:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d6xvuggapt1evr06isus.png)

Ou para criar com quartos, banheiros e um quintal faremos da seguinte forma: 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7kdll2ybortilrmjfwci.png)

Além disso, ao passar o mouse em cima do objeto já sabemos exatamente o que tem dentro da casa:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rjfwwwaw3rdqi1zgjfni.png)

Eu utilizei uma implementação similar a esta no backend do meu trabalho atual, para criar um serviço de parâmetros dinâmico. É um excelente jeito de simplificar tipagens complexas e ter mais controle e validação do que está sendo construído de forma dinâmica em tempo desenvolvimento.