[Typescript] Step6: Types at Runtime
Step 5: Types at Runtime
This problem often happens when APi return the data.
let cachedAllTeamsList: Promise<ITeam[]>;
export async function getAllTeams(): Promise<ITeam[]> {
if (typeof cachedAllTeamsList === 'undefined')
cachedAllTeamsList = apiCall('teams');
return await cachedAllTeamsList;
}
In this line of code: apiCall('teams');
It is actually Promise<any>
, and because we set cachedAllTeamsList: Promise<ITeam[]>
, we cannot make sure whether there is any wired types going on.
Way to solve the problem is by: asserting and throw if the types we want is different.
function isITeam(arg: any): arg is ITeam {
/**
* {
iconUrl: string;
name: string;
id: string;
channels: IChannel[];
}
*/
return (
typeof arg.iconUrl === 'string' &&
typeof arg.name === 'string' &&
typeof arg.id === 'string' &&
Array.isArray(arg.channels)
);
}
function assertIsTypedArray<T>(
arg: any,
check: (val: any) => val is T,
): asserts arg is T[] {
if (!Array.isArray(arg)) {
throw new Error(`Not an array: ${JSON.stringify(arg)}`);
}
if (arg.some((item) => !check(item))) {
throw new Error(`Violators found: ${JSON.stringify(arg)}`);
}
}
let cachedAllTeamsList: Promise<ITeam[]>;
export async function getAllTeams(): Promise<ITeam[]> {
if (typeof cachedAllTeamsList === 'undefined')
cachedAllTeamsList = apiCall('teams').then((teams) => {
assertIsTypedArray(teams, isITeam);
return teams;
});
return await cachedAllTeamsList;
}