typescript - Type dynamisk objektsfunksjoner kall
Jeg har denne koden (Playground):
const routes = {
projects: ({}) => "/projects",
"projects.edit": ({ id }: { id: string }) => `/projects/${id}`,
report: ({ projectId }: { projectId: string }) => `/report/${projectId}`,
};
type Routes = typeof routes;
export function generateUrl<Name extends keyof Routes>(
name: Name,
params: Parameters<Routes[Name]>[0]
): string {
const fn = routes[name];
return fn(params);
}
Jeg får denne feilen på linje fn(params). Hvordan ville jeg skrevet det for å type-sjekke (uten å bruke any)?
Egenskapen 'id' mangler i typen '{ projectId: string; }' men kreves i typen '{ id: string; }'.
Svar #1
Her er en annen løsning
Dette lar deg ha ruter som tar flere parametere.
type Route = (...args: any[]) => string;
type Routes = {
[index: string]: Route;
};
function createUrlGenerator<T extends Routes>(router: T) {
return <K extends keyof T>(name: K, ...params: Parameters<T[K]>): string => {
return router[name].apply(null, params);
}
}
const routes = {
projects: ({}) => "/projects",
"projects.edit": ({ id }: { id: string }) => `/projects/${id}`,
report: ({ projectId }: { projectId: string }) => `/report/${projectId}`,
multyParams: (id: number, query: string) => `${id}/${query}`
};
export const generateUrl = createUrlGenerator(routes);
generateUrl('multyParams', 123, '43');
generateUrl('multyParams', 123); // Exception
generateUrl('projects.edit', { id: '123' });
generateUrl('projects.edit', { id: 123 }); // Exception
Svar #2
const routes = {
projects: ({}) => "/projects",
"projects.edit": ({ id }: { id: string }) => `/projects/${id}`,
report: ({ projectId }: { projectId: string }) => `/report/${projectId}`,
};
type Routes = typeof routes;
export function generateUrl<Name extends keyof Routes>(
name: Name,
params: Parameters<Routes[Name]>[0]
): string {
const fn = routes[name] as ((p: typeof params => ReturnType<Routes[Name]>);
return fn(params);
}Se lekeplass.
I utgangspunktet er greia at når man henter funksjonen fra routes, vil TS være ekstremt sikker og tvinger den hentede verdien til å bli kalt med skjæringspunktet av alle mulige parametertyper, eller {} & {id: string} & {projectId: string} i dette tilfellet, som oversettes til {id: string, projectId: string}.
Dette er åpenbart ikke ønsket her, så vi bruker en typesikker1 konvertering.
Merk imidlertid at det er en ulempe. Tilstedeværelsen av 'projects'-ruten uten noen parameter gjør følgende linje ok:
fn(42)
Skulle dette være et problem, vil fjerning av den bare ruten løse det.
1: Prøv å erstatte typeof params med number.
