我正在尝试将所有类型的与API相关的功能都基于一个定义,以简化一些常见的用例并使事情更加透明。例如:
// TypeScript 3.4.3
type API =
{route: "helloWorld", method: "get", parameters: {}, result: string}
| {route: "echo", method: "get", parameters: {arg: string}, result: {response: string}}
type GETParameters<R> = Extract<API, {route: R, method: "get"}>["parameters"];
// const a: GETParameters<"echo"> = 42; // fails, as expected
const a: GETParameters<"echo"> = {arg: "hello"}; // works, as expected
在上述情况下,它可以按预期工作,但是如果没有在以下情况下相关的类型注释,我将无法使其工作。
function f<R>(route: R, paramF: (p: GETParameters<R>) => any){
return 0
}
// f<"echo">("helloWorld", p => p.arg) // fails, as expected
// f<"echo">("echo", p => p.something) // fails, as expected
f<"echo">("echo", p => p.arg) // works, as expected, but very ugly in extreme cases
f("echo", p => p.arg) // fails, why?
//inferred: f(route: string, paramF: (p: {} | { arg: string; }) => {}): number
我假设类型检查器分别在R
中推断f<R>
的两个实例,但是我不知道如何从这两个参数(最好是路由)中推断出这两个实例。
答案 0 :(得分:0)
Typescript不会扩展类型参数的字符串文字类型,除非它扩展了string
(其他文字类型也是如此)。如果将约束添加到R
,它将按预期工作。您可以使用string
(它将推断出适当的文字类型),但是在您的情况下,我认为使用可能路由的确切并集会更好,那就是API['route']
// TypeScript 3.4.3
type API =
{route: "helloWorld", method: "get", parameters: {}, result: string}
| {route: "echo", method: "get", parameters: {arg: string}, result: {response: string}}
type GETParameters<R> = Extract<API, {route: R, method: "get"}>["parameters"];
//This also works:
//function f<R extends string>(route: R, paramF: (p: GETParameters<R>) => any){
function f<R extends API['route'] >(route: R, paramF: (p: GETParameters<R>) => any){
return 0
}
f("echo", p => p.arg)