类型动态对象函数调用

时间:2019-10-25 08:10:09

标签: typescript

我有此代码(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);
}

我在第fn(params)行中收到此错误。我将如何编写它进行类型检查(不使用any)?

  

类型'{projectId:string;中缺少属性'id' }”,但在类型“ {{id:string; }'。

2 个答案:

答案 0 :(得分:3)

这是另一种解决方案
这样一来,您就可以采用带有多个参数的路由。

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

答案 1 :(得分:0)

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);
}

请参见playground

基本上,事情是从routes检索函数时,TS希望非常安全,并强制使用所有可能的参数类型或此处的{} & {id: string} & {projectId: string}的交集来调用检索到的值。大小写,即为{id: string, projectId: string}

在这里显然不希望如此,因此我们使用类型安全的 1 强制类型转换。

但是请注意,这有一个缺点。 'projects'路由的存在(不带任何参数)使以下行没问题:

fn(42)

如果这是一个问题,那么删除裸露的路由就可以解决。


1:尝试将typeof params替换为number