Executando verificação de segurança...
2

[ Conteúdo ] Functions overload { TypeScript }

Introdução

Hoje venho falar sobre um tópico que pode ser muito confuso para quem tá começando, ou se você é mais experiente e só deu um "skip" para um próximo assunto pois não entendeu este aqui. Functions overload é uma possibilidade muito interessante e fléxivel com vantagens e desvantagens no TypeScript

Observações: Estarei falando especificamente do TypeScript e apenas. Se existir uma forma semelhante, ou este tópico esteja presente em outros linguagens, mas com abordagens diferentes, eu não entrarei a fundo. Cobrirei o tópico apenas e unicamente sobre o TypeScript. Sem mais delongas.

O que é Function overload?

É difícil definir isso, pois é algo que se entende mais fazendo, do que falando. Mas vamos lá, darei minha própria definição sobre: Functions Overloads são uma técnica que nos permite reaproveitar funções de uma maneira específica, porém, com suas flexibilidades.

Mas o que é exatamente essa técnica que reaproveita as funções? Primeiro, vou deixar alguns pontos importantes: De fato, reaproveita uma mesma função, entretanto, pode ser mais argumentativo, ou até mais lento. Segundo: É uma técnica que é mais como uma alternativa, então, provavelmente deve ter algo ou uma forma semelhante ou melhor de fazer isso. Algumas vezes, pode ficar a seu critério.

Sintaxe:

A sintaxe é a mesma do dia a dia, nada de muito novo. Irei da um exemplo, porém, não sinta-se na necessidade de entender em primeiro instância:

function teste(n: number): number;
function teste(n: string, x:string, z:string): string;
function teste(n: number | string, x?:string, z?:string):number | string {
    if(typeof n === 'string' && typeof x === "string" && typeof z === "string") {
        console.log("it's a string!")
        return "my String Returned!"
    } else {
        console.log("it's a number!")
        return "My number returned!"
    }
}

teste(10)  
teste("string1", "string2", "string3") 

Se você tem um bom olho, notou que as três funções tem o mesmo nome, mas, como assim? Isso não deveria estar errado? Se fosse em javaScript, estaria errado, provavelmente (não testei). Se colar o código no playground do TypeScript neste link aqui: Playground vai ver que não tem nenhum erro.

vou abstrair todo esse código, que eu mesmo criei justamente para explicar neste artigo.
Primeiro de tudo, vamos começar olhando para a primeira linha do código.

function teste(n: number): number;

Nós temos uma função com o nome "teste" que tem um único argumento do tipo number e que retorna number também.

Já na segunda linha temos algo parecido:

function teste(n: string, x:string, z:string): string;

Uma função com o mesmo nome com três argumentos cujo tem todos o tipo string, que retorna uma string.

A parte boa começa aqui:

function teste(n: number | string, x?:string, z?:string):number | string {
    if(typeof n === 'string' && typeof x === "string" && typeof z === "string") {
        console.log("it's a string!")
        return "my String Returned!"
    } else {
        console.log("it's a number!")
        return "My number returned!"
    }
}

Uma função com o mesmo nome, só que com diferenças. Primeiro a função tem uma lógica dentro do bloco, diferente das outras, e tem um unio de retorna para uma string e number.

Ok! Mas eu não entendi ainda o que é tudo isso! Eu fiz isso, para você olhar o código por parte, e conseguir visualizar melhor o código, ao invés de ver como um todo e tomar um susto.

As duas primeira linhas do código, são functions overload e a terceira linha é uma function signature. Todas as três são intimamente relacionadas.

A primeira função basicamente fala para o typeScript: "Olha, a função "teste" pode receber um único paramêtro do tipo number e que retorne number também, se não for assim, lançará um erro."

Já a segunda função diz para o TypeScript: "Meu chapa, além da possibilidade de cima, considere que a função teste pode também receber três paramêtros do tipo string e que retorne uma string. Se por acaso for diferente desde padrão, retorne um erro caso não se encaixe no meu padrão, ou no padrão de cima"

Já a terceira função signature, é como o carinha que vai implementar a lógica, com base no que as funções pedem.

Tá difícil ainda de entender? Então vamos analisar o código mais uma vez:

function teste(n: number): number;
function teste(n: string, x:string, z:string): string;
function teste(n: number | string, x?:string, z?:string):number | string {
    if(typeof n === 'string' && typeof x === "string" && typeof z === "string") {
        console.log("it's a string!")
        return "my String Returned!"
    } else {
        console.log("it's a number!")
        return "My number returned!"
    }
}

teste(10)  
teste("string1", "string2", "string3") 

Vamos focar na função signature, que á terceira função. Ela é responsável, como eu disse acima, por fazer as coisas acontecerem.

Observe que o primeiro paramêtro n é declaro como sendo number e string nas funções de overload. Na function signature, para o TypeScript não reclamar, fazemos a únião desde tipos afirmando para o TypeScript que o valor do paramêtro ou é do tipo number ou do tipo string.

Se você tem dúvidas sobre o que é união de tipos, então talvez este seja um tópico muito avançando para você, vã na documentação e procure por every types, Narrowing e também se encontra presente em diversas outras partes da documentação.

Entendemos o que ocorre no primeiro paramêtro, então não é díficil de entender os outros dois que são x e z, que se olhar bem, são paramêtros opicionais. Esses dois são paramêtros opcionais por porquê na primeira funções overload, só tem um argumento presente, o que não é a mesma coisa pra a segunda função que possui os três argumentos, sacou?

Resumido, os paramêtros são opcionais, pois no primeiro caso eu tenho apenas 1 e não 3 paramêtros. Se eu não colosse os paramêtros como opcionais, então quando eu quisesse que a função caisse na primeira possibilidade, iria pedir 3 paramêtro, e iria lançar um typeErro pois foi determinado que deveria ser apenas 1.

A função pode retorna number ou string, dependendo do caso. Isso porque a primeira função overload tem um retorno do tipo number, e a segunda do tipo string. Se você já tem uma experiência com TypeScript, sabe que vai da um erro, caso não especique bem o retorno.

Dentro do bloco do código tem uma lógica que vai ser executada com base no valor recebido nos paramêtros:

function teste(n: number | string, x?:string, z?:string):number | string {
    if(typeof n === 'string' && typeof x === "string" && typeof z === "string") {
        console.log("it's a string!")
        return "my String Returned!"
    } else {
        console.log("it's a number!")
        return "My number returned!"
    }
}

Aqui o TypeScript entende que a condicional é um Typeguard que basicamente, tenta saber o valor de retorno com precisão, para mais detalhes consulte a documentação na parte de Narrowing

Agora, que já expliquei tudo detalhadamente, já ficou bem longo inclusive, vamos para a conclusão:

function teste(n: number): number;
function teste(n: string, x:string, z:string): string;
function teste(n: number | string, x?:string, z?:string):number | string {
    if(typeof n === 'string' && typeof x === "string" && typeof z === "string") {
        console.log("it's a string!")
        return "my String Returned!"
    } else {
        console.log("it's a number!")
        return "My number returned!"
    }
}

teste(10)  
teste("string1", "string2", "string3") 

Quando a gente chama a função teste(10), vai cair na primeira possibilidade, ou seja, o TypeScrip vai entender que você tá querendo essa posibilidade aqui:

function teste(n: number): number;

Depois que chamar a função com um argumento do tipo number, vai executar o bloco de código e vai cair na segunda condição, do else.

O mesmo se aplica para a chamada de: teste("string1", "string2", "string3") que tem 3 argumento, todos do tipo string, e cai exatamente na segunda função de overload:
function teste(n: string, x:string, z:string): string;
Notou que é basicamente, chamar a função com os argumento correspondentes? O papel das funções de overload é "configurar" ou melhor, "especificar" quais são os possíveis argumentos que a função pode receber. Lembrano que podem ter muitos outros tipoes de funções overloads e mais de duas funções. Só não esquece de Typar tudo certinho.

Há, se vocè tentar fazer isso aqui: teste("teste") vai resultar em um erro, pois não tem nenhu function overload que recebe um único paramêtro do tipo strig. Se tentar fazer isso aqui: teste("string1", "string2") também vai da erro pois não tem nenhuma função que recebe apenas dois argumentos do tipo string. Só existe funções que recebe um único paramêtro do tipo number, ou recebe três argumentos do tipo string, apenas.

Conclusão:

Alguma dúvida pessoal? Comentem!

Carregando publicação patrocinada...