Constraints on interface members in typescript generics

微笑、不失礼 提交于 2019-12-01 21:12:37

T's constraint can refer to T (with some restrictions), so you can use a mapped type to generate a constraint that has the same fields as T:

function interpolateParams<T extends {[P in keyof T] : string | number}>(
    route: string, 
    params: T) : string { /*...*/ }

Beware that trickery with circular type parameter constraints can sometimes cause problems, though this scenario will likely be OK.

Here is final version, thanks Matt for hint

static interpolateParams(
    route: string, 
    params: {[key: string] : string | number}) : string {

    const parts = route
        .split("/")
        .map(part => {
            const match = part.match(/:([a-zA-Z09]*)\??/);
            if (match) {
                if (!params[match[1]]) {
                    if (part.endsWith("?")) {
                        return null;
                    }

                    console.error("route argument was not provided", route, match[1]);
                    return part;
                }

                return params[match[1]];
            }
            else {
                return part;
            }
        }).filter(p => p && p != "");

    return "/" + parts.join("/");
}

static formatRoute<T extends {[P in keyof T] : string | number}>(
    route: string,
    params: T
) : string {
    return interpolateParams(route, params);
}

If you want interpolateParams("/api/:method/:value", {method: "abc", value: 10}); to typecheck you can't. This is because you cannot infer anything about "/api/:method/:value" to give you a method,value signature.

Workaround

Write functions that take method and value and use it to power both the config and the use.

E.g. this is the strategy I use with takeme.

// Define 
export const links = {
  profile: (id: string) => `/profile/${id}`
}

// Use in Configure 
links.profile(':profileId')

// Use in Navigate / a tags
links.profile(user.id)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!