在typescript中基于可选参数的类型泛型

q1qsirdb  于 2023-08-07  发布在  TypeScript
关注(0)|答案(2)|浏览(146)

我有一个泛型函数foo(),它有一个可选参数fn,可以是一个转换返回值的函数。如果未提供fn,则只需使用string。比如说

const foo = <T>(fn?: (data: string) => T) => {
  const data = "some data"
  if (!fn) {
    return String(data)
  }
  
  return fn(data)
}

字符串
我很难让泛型正确地推断返回值。如果未提供fn,则返回值应推断为string。如果是,则返回值应推断为fn的任何返回类型。
目前,如果我调用foo(),返回类型是unknown。如果我提供一个fn,返回类型总是推断为string | (return type of fn),在这种情况下,应该删除string

watbbzwu

watbbzwu1#

如果我理解正确的话,TS中有一些变通方法可以使用conditional typesfunction overloads来实现您的目标。通过使用函数重载,可以根据是否提供fn参数来定义不同的返回类型。

type ReturnOrTransform<T> = T extends ((data: string) => any) ? ReturnType<T> : string;

function foo<T extends ((data: string) => any)>(fn: T): ReturnOrTransform<T>;
function foo<T extends undefined>(fn?: T): string;
function foo<T extends ((data: string) => any) | undefined>(fn?: T): ReturnOrTransform<T> | string {
  const data = "some data";
  if (!fn) {
    return String(data) as ReturnOrTransform<T> | string;
  }
  return fn(data);
}

const result1 = foo(); // type of result1 is string

const transformFn = (data: string) => ({ length: data.length });
const result2 = foo(transformFn); // The inferred type of result2 is { length: number }

字符串
你可以在那里玩

z9smfwbn

z9smfwbn2#

您可以为泛型T设置一个默认值,就像您的例子中的T = string一样。当一个参数被传递给你的函数foo时,它的返回类型将是T。如果不带任何参数调用foo,则T的默认值将是返回类型string

const foo = <T = string>(fn?: (data: string) => T) => {
  const data = "some data";
  if (!fn) {
    return String(data) as T;
  }
  
  return fn(data);
};

const result1 = foo();  // Inferred as string
const result2 = foo(_ => 5);  // Inferred as number
const result3 = foo(_ => false);  // Inferred as boolean

字符串
TypeScriptPlayground

相关问题