Skip to content

Instantly share code, notes, and snippets.

@gcorreaq
Last active December 17, 2020 07:58
Show Gist options
  • Save gcorreaq/593381b026aeb093dd3a866d15299875 to your computer and use it in GitHub Desktop.
Save gcorreaq/593381b026aeb093dd3a866d15299875 to your computer and use it in GitHub Desktop.
Filter flavor text for the Poke API
fetch("https://pokeapi.co/api/v2/pokemon-species/2").then((result) => {
result.json().then((data) => {
// We filter the array of flavor texts only for the ones that have the language `en`
const fileterdFlavorTextEntries = data.flavor_text_entries.filter(
(element) => element.language.name === "en"
);
// If there's any entries, let's get the first one
const flavorTextEntry = fileterdFlavorTextEntries.length > 0 ? fileterdFlavorTextEntries[0] : {};
console.log(flavorTextEntry);
// If we want, we can reassign the `flavor_text_entries` array to one with just the entry we have
data.flavor_text_entries = [flavorTextEntry];
console.log(data);
// Or if we just want the flavor text itself
const flavorText = flavorTextEntry.flavor_text;
console.log(flavorText)
});
});
// This is an incomplete type declaration in purpose. I don't want to type the properties that I don't care about
type Pokemon = {
flavor_text_entries: FlavorTextEntry[],
}
// Half-way defined type, just for the sake of having the important bits
type FlavorTextEntry = {
flavor_text: string,
language: {
name: string,
},
version: {
name: string,
}
};
async function getPokeData(id: number): Promise<Pokemon> {
// This function just gives us the pokemon data
const result = await fetch(`https://pokeapi.co/api/v2/pokemon-species/${id}`);
return await result.json();
}
function getFlavorText(pokemon: Pokemon): string | null {
// This will either return the flavor text for a pokemon, or just return null
// Get the filtered flavor text entries
const fileterdFlavorTextEntries: FlavorTextEntry[] = pokemon.flavor_text_entries.filter(element => element.language.name === 'en');
// Get the first entry (if we got any)
return fileterdFlavorTextEntries?.[0]?.flavor_text;
}
getPokeData(2).then(pokemon => {
const flavorText = getFlavorText(pokemon);
console.log(flavorText)
});
// This is an incomplete type declaration in purpose. I don't want to type the properties that I don't care about
type Pokemon = {
flavor_text_entries: FlavorTextEntry[],
name: string,
names: NameEntry[],
order: number,
};
// Basic type for types that will have language data
type LanguageData = {
language: {
name: string,
},
};
// Half-way defined type, just for the sake of having the important bits
// Note that we merge this type declaration with LanguageData to have all the properties we need
type FlavorTextEntry = {
flavor_text: string,
version: {
name: string,
},
} & LanguageData;
// Half-way defined type, just for the sake of having the important bits
// Note that we merge this type declaration with LanguageData to have all the properties we need
type NameEntry = {
name: string,
} & LanguageData;
async function getPokeData(id: number): Promise<Pokemon> {
const result = await fetch(`https://pokeapi.co/api/v2/pokemon-species/${id}`);
return await result.json();
}
function getFieldText<T extends LanguageData, K extends keyof T>(data: T[], field: K): T[K] | null {
/*
This function is generic: It filters the array `data[]` (with whatever types it has)
where `data[].language.name` is in English, and from the first entry it found, it will return the value
in the property `field`
For example:
data = [
{
language: {
name: 'en'
}
name: 'Gonchimon'
},
{
language: {
name: 'es'
},
name: 'El terrible Gonchimon'
}
]
T is the type given by each object, and it extends LanguageData (because each object has a `language` property)
K will be any property of any of the objects in the array data (so, any key from any T in the array data)
It will return any value from one of the properties of the objects `T` in data, or null if nothing was found
*/
const fileterdTextEntries = data.filter(element => element.language.name === 'en');
return fileterdTextEntries.length > 0 ? fileterdTextEntries[0][field] : null;
}
getPokeData(2).then(pokemon => {
console.log(`Got data for pokemon with ID ${pokemon.order}`)
// The magic of typing the function `getFieldText` comes up when typechecking: here we cannot use as a second parameter
// something that is not defined in the type for the field `names` (the type `NameEntry` only defines properties `name`
// and `language`)
const pokemonName = getFieldText(pokemon.names, 'name');
console.log(`The pokemon's name is ${pokemonName}`);
// The magic of typing the function `getFieldText` comes up when typechecking: here we cannot use as a second parameter
// something that is not defined in the type for the field `flavor_text_entries` (the type `FlavorTextEntry` only defines
// the properties `flavor_text`, `language` or `version`)
const flavorText = getFieldText(pokemon.flavor_text_entries, 'flavor_text');
console.log(`The pokemon's flavor text is ${flavorText}`);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment