如何在多个功能参数中推断相同类型

时间:2019-05-16 14:28:12

标签: typescript types

我正在尝试将所有类型的与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>的两个实例,但是我不知道如何从这两个参数(最好是路由)中推断出这两个实例。

1 个答案:

答案 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)