Imagine que você tem a seguinte situação:
Você tem uma aplicação que busca por músicas no Spotify e nessa aplicação você mostra o
Você então cria 2 funções para acessar a API do Spotify
-
getUserpara chamar a API que irá buscar os dados do usuário -
getSongque irá retornar uma lista de músicas do Spotify
Então você teria o seguinte código:
type APIResponse<T> = {
data: T;
error: Error;
}
type User = {
email: string;
}
type Song = { id: string; title: string };
const getUser = async (fetchUrl: string): APIResponse<User> => {
const res = await fetch(fetchUrl);
return res;
}
const getSong = async (fetchUrl: string): APIResponse<Song> => {
const res = await fetch(fetchUrl);
return res;
}
Depois de implementar as 2 funções, você percebe que elas são muito parecidas. As 2 recebem uma url que é passada para dentro do método fetch. Esse método faz a chamada para a API e depois retorna o resultado.
E aí, você pode pensar
poxa, já que elas são tão parecidas, acho que vou criar uma função que reduz a quantidade de código repetido
const fetchApi = async (fetchUrl: string): APIResponse<User | Song> => {
const res = await fetch(fetchUrl);
return res;
}
const userResppnse = await fetchApi('https://apiUser...');
const songResponse = await fetchApi('https://apiSong...');
Já parece que ficou melhor. Agora temos menos código duplicado e menor possibilidade de erro.
Mas você vai ter um problema de Typescript 😟
O tipo da variável userResponse está como APIResponse<User | Song> então se você tentar fazer isso:
const userResponse = await fetchApi('https://...');
console.log(userResponse.data.email);
Você vai tomar o seguinte erro:
Property 'email' does not exist on type 'User | Songs[]'.
Property 'email' does not exist on type 'Songs[]'
O Typescript não consegue dizer se a propriedade data da variável userResponse é um User ou um Song e por isso ele previne que você chame a propriedade email que é exclusiva do User.
Isso garante que se por exemplo isso acontecer:
const userResponse = fetch('https://apiSong...');
Você não vai ter problemas mais pra frente.
Type guards
Os type guards são uma forma de dizer para o Typescript qual tipo nós esperamos.
Podemos criar um type guard de usuário que garante o tipo User da seguinte forma:
const isUser = (data: User | Song): data is User => (data as User).email !== undefined;
Estamos criando a função isUser que aceita o tipo data: User | Song e que retorna um data is User. A expressão is User diz que eu, como desenvolvedor, garanto que o retorno da minha função é do tipo User.
O que falta é a implementação dessa verificação. Já que o tipo Song não tem o campo email podemos verificar se a variável data possuí ele.
Se possuir, podemos dizer que data é do tipo User.
E com isso, podemos executar o seguinte código sem problemas de Typescript:
if(isUser(userResponse.data)) {
console.log(userResponse.data.email)
};
Assim, o Typescript não vai mostrar um erro porque você disse que a função isUser retorna User e nada mais.
Não tem possibilidade da variável data ser do tipo Song por exemplo.
E para finalizar, o type guard do tipo Song seria assim:
const isSong = (data: User | Song): data is Song => (data as Song).title !== undefined;
if(isSong(songResponse.data)) {
console.log(songResponse.data.title);
}
Através dos type guards você consegue ter maior controle sobre a tipagem do seu código. Tudo isso em tempo de runtime, o que é bem legal 🤘
Apesar de ser uma boa adição na sua base de código, o
type guardsé propenso a falhas já que quem define a função para validar o tipo é o próprio desenvolvedor.Para resolver essas falhas e realmente trabalhar com um
typcheckingemruntime, sugiro dar uma lida nesse artigo do pessoal do Unsplash. O artigo destaca o porquê detype guardsdefinidos pelo usuário não serem tão seguros e o que fazer nesses casos.
Galera, é isso por hoje. Fiz esse artigo porque acabei me deparando com algumas situações na minha aplicação que funcionariam melhor se tivesse um type guard implementado. E apesar de serem muito úteis, não vejo muita gente usando no dia a dia, então fica aqui minha contribuição. Espero que consigam aproveitar de alguma forma 😉
E se vocês sentiram falta de alguma explicação, ficaram com alguma dúvida ou só querem trocar uma ideia, podem me marcar ou mandar DM no twitter 🤙
Top comments (0)