Builder de tipagem dinâmica com fluent api no typescript

Pedro Santos - Jun 29 - - Dev Community

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

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

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

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 CasaPropsK.

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

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

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

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

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

Image description

Nossa classe ficou da seguinte forma:

Image description

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

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

Image description

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

Image description

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.

. .