代码之家  ›  专栏  ›  技术社区  ›  Totty.js

泛型api类型的Typescript?

  •  -1
  • Totty.js  · 技术社区  · 8 年前

    例如,api是这样的 api('serviceName', {data: 1}) ,这是由api的客户端调用的。请注意,客户机不一定与服务器在同一台计算机上运行。

    api 看起来像:

    export const api = async (type: string, payload: Object) => {
      const res: any = await request
        .post(`someurl.com/api`)
        .json({data: ejson.stringify({type, payload})});
      return res;
    };
    

    服务器端如下所示:

    const apiRemote = (apiName, apiInput) => {
      return apiList[apiName](apiInput)
    }
    

    注意,客户机不能包含 apiRemote 直接归档。

    我怎么才能做这个 应用程序编程接口

    类似但在flowtype中: https://flow.org/try/#0MYewdgzgLgBBCmAnAbgS2PCAWGBeGA3gFAwwCGAXORAJ5jAwAUZiA5hFQQBbw1VgBXALYAjJAF8AlFQAKiEENQIAPAUoxBoiQD48u4qVKJ4UAYjCESh0uoDMOAFTk2EAHQ8aAGiulxAbitxb1IRKjJaeiYWdk4eABs4kCpoRFQwVilZeUUVAlC4KFT08V1cfR8YY1NzS2sQqgADCAATZoaYAGpndnd4BJBgw39A72GiAHpxmCguJRgAMwF6KFRwGDmwEFhWEDTWaZAYMRgBBGajmmmeGAAHeQAreGBYOfvT2HmQRBgJqfnEgDurhgACFwugyAlLjM5nMyEdUs1WPAjiYAfB4BZgHFUJjYBBUM0UWQwOcECgkHBCfBXL8YAB1LiHYCQuIQK6YFEshLsuZrGZcnF4qlEzxHASwAUIBZLZ6rSB08BxS6IJYwfnXcnISkEom00CQD5gHD4cJ0BjMBIAQRcVAA8iJHs9JHpapUTGYLFr0JgsABtVk2noAa14AF1LXEg25ohBJAExkRmBELS6ym6DdAYMhIQJ4Fa8OQAWRUEasIwCKG+DAGmQGmLY7FeFQsOIpAFSIwc3E81bXOpNGJEPGYJM4EyBHFzgA5O0AFQWJbiVi7ufz-eShT2I7HEAnU8XqGXpCsmdg3bzIMLZGLpYWxorVcaInr3Q4hHiiUaEAgDTb8ZXC94BBVx8hSbc-FHKY9xAScZ3nQ9jyYICQPyQckB3aD93OeYlyIKRGHjIA

    interface S1 {
      name: 's1',
      input: number,
      output: number,
    }
    
    interface S2 {
      name: 's2',
      input: string,
      output: string,
    }
    
    interface List {
      s1: S1;
      s2: S2;
    }
    
    const a = async () => {
      type Api = <T extends keyof List>(name: T, input: List[T]['input']) => List[T]['output'];
      const api: Api = window["api"];
      const x: number = await api("s1", 2);
      const y: string = await api("s2", 's');
    };
    

    问题是我不喜欢这样格式化S1和S2。我喜欢这样:

    type S1 = (input:Input):Output

    或者类似的东西。

    编辑2:

    interface S1 {
      name: 's1',
      input: number,
      output: number,
    }
    
    interface S2 {
      name: 's2',
      input: string,
      output: string,
    }
    
    type Service<T extends { input: any, output: any }> = (input: T['input']) => Promise<T['output']>
    
    // I'd like not to have this one because now I have to enforce manually that
    // s1 key in List is the same as S1["name"].
    // I think makes sense for the name to be in the S1 not in this List.
    interface List {
      s1: S1;
      s2: S2;
    }
    
    // I'd like to keep it in this format instead
    type S = S1 | S2;
    
    const a = async () => {
      // But in this place, if I replace `List[T]` with `S['input']` will lose the types.
      type Api = <T extends S["name"]>(name: T, input: List[T]['input']) => Promise<List[T]['output']>;
      const api: Api = window["api"];
      const x: number = await api("s1", 2);
      const y: string = await api("s2", 's');
    };
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   Matt McCutchen    8 年前
    interface List {
      s1: (input: number) => number;
      s2: (input: string) => string;
    }
    
    // https://github.com/Microsoft/TypeScript/pull/26243
    type Parameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;
    
    const a = async () => {
      type Api = <T extends keyof List>(name: T, ...input: Parameters<List[T]>) => ReturnType<List[T]>;
      const api: Api = window["api"];
      const x: number = await api("s1", 2);
      const y: string = await api("s2", 's');
    };
    

    好的,如果你想这样做,你可以用这段代码来构造 List S

    // Distributive conditional type to look at each union constituent of `S`
    // and keep the one with the name we are looking for.
    type Lookup<SS, K> = SS extends { name: infer N } ? N extends K ? SS : never : never;
    type List = {
        [K in S["name"]]: Lookup<S, K>
    };
    

    有关条件类型的进一步阅读,请参阅 handbook .

    推荐文章