【问题标题】:TypeScript Generic function return type issueTypeScript 通用函数返回类型问题
【发布时间】:2020-01-07 11:20:55
【问题描述】:

我想通过 TypeScript 泛型定义函数返回类型。所以R 可以是我定义的任何东西。

... Promise<R | string> 不是我的解决方案。

错误

错误:(29, 9) TS2322:类型“字符串”不可分配给类型“R”。 “string”可分配给“R”类型的约束,但“R”可以用约束“{}”的不同子类型来实例化。

import { isString, } from '@redred/helpers';

interface P {
  as?: 'json' | 'text';
  body?: FormData | URLSearchParams | null | string;
  headers?: Array<Array<string>> | Headers | { [name: string]: string };
  method?: string;
  queries?: { [name: string]: string };
}

async function createRequest<R> (url: URL | string, { as, queries, ...parameters }: P): Promise<R> {
  if (isString(url)) {
    url = new URL(url);
  }

  if (queries) {
    for (const name in queries) {
      url.searchParams.set(name, queries[name]);
    }
  }

  const response = await fetch(url.toString(), parameters);

  if (response.ok) {
    switch (as) {
      case 'json':
        return response.json();
      case 'text':
        return response.text(); // <- Error
      default:
        return response.json();
    }
  }

  throw new Error('!');
}

export default createRequest;

【问题讨论】:

  • 您打算如何使用此功能?您是否希望某人能够调用 createRequest&lt;number&gt;(/*some arguments*/) 并让您的函数返回一个解析为数字的承诺?
  • 你尝试使用'await fetch

    (url.toStrin(), paramters)'

  • 错误是因为,如果你将 R 定义为另一个不是字符串的东西,这个函数可能会返回一个字符串的承诺而不是 R 的承诺(如果 as=='text')所以该函数不符合定义。
  • @NicholasTower 是的

标签: typescript


【解决方案1】:

我可能会使用overloads 来表示调用方的这种区别......如果调用方指定"text",那么返回类型肯定是Promise&lt;string&gt;,并且函数在R 中不再是通用的。

除此之外:TypeScript 命名约定通常为泛型类型参数保留单字符大写名称(尤其是 TUKP),所以我会将您的 P 扩展为 @987654332 @。此外,标识符as 是有问题的,因为它是 TypeScript 中的保留字,可能会混淆 IDE 或编译器;在下文中,我将用az 替换as。好的,所以你的界面是

interface Params {
  az?: "json" | "text";
  body?: FormData | URLSearchParams | null | string;
  headers?: Array<Array<string>> | Headers | { [name: string]: string };
  method?: string;
  queries?: { [name: string]: string };
}

这是我要使用的重载。一个非通用调用签名只接受"text" 中的az,另一个在R 中是通用的,并且只接受"json"undefined/missing 中的az实现 签名可以涉及R | stringany 或任何你想要的,因为它在调用者方面是不可见的。

async function createRequest(
  url: URL | string,
  { az, queries, ...parameters }: Params & { az: "text" }
): Promise<string>;
async function createRequest<R>(
  url: URL | string,
  { az, queries, ...parameters }: Params & { az?: "json" }
): Promise<R>;
async function createRequest<R>(
  url: URL | string,
  { az, queries, ...parameters }: Params
): Promise<R | string> {
  if (isString(url)) {
    url = new URL(url);
  }

  if (queries) {
    for (const name in queries) {
      url.searchParams.set(name, queries[name]);
    }
  }

  const response = await fetch(url.toString(), parameters);

  if (response.ok) {
    switch (az) {
      case "json":
        return response.json();
      case "text":
        return response.text(); // <- okay now
      default:
        return response.json();
    }
  }

  throw new Error("!");
}

下面是我们如何使用它来获取文本:

const promiseString = createRequest("str", { az: "text" }); // Promise<string>

下面是我们如何使用它来获取其他类型(这要求调用者指定R,因为它无法推断):

interface Dog {
  name: string;
  age: number;
  breed: string;
  fleas: boolean;
}

const promiseDog = createRequest<Dog>("dog", {}); // Promise<Dog>

请注意,如果您指定了R,则不能要求"text"

const notGeneric = createRequest<Dog>("dog", {az: "text"}); // error!
//                                     -----> ~~
// "text" is not assignable to "json" or undefined

好的,希望对您有所帮助。祝你好运!

Link to code

【讨论】:

  • 您的解决方案很有魅力,但我还有另一个问题。你能帮我么?我将您的解决方案用于 createRequest 函数,但它在其他地方不起作用。 stackoverflow.com/questions/57800985/…
猜你喜欢
  • 1970-01-01
  • 2021-03-24
  • 1970-01-01
  • 2019-02-10
  • 2020-04-27
  • 2021-11-01
  • 1970-01-01
  • 2019-12-29
  • 2020-02-11
相关资源
最近更新 更多