为什么TypeScript没有以正确的方式支持函数重载?

13 浏览
0 Comments

为什么TypeScript没有以正确的方式支持函数重载?

在Typescript中,关于函数重载的工作原理存在很多问题(例如,TypeScript函数重载)。但是没有问题是像“为什么它以那种方式工作?”\n现在函数重载的写法是这样的:\n

function foo(param1: number): void; 
function foo(param1: number, param2: string): void;
function foo(...args: any[]): void {
  if (args.length === 1 && typeof args[0] === 'number') {
    // implementation 1
  } else if (args.length === 2 && typeof args[0] === 'number' && typeof args[1] === 'string') {
    // implementation 2
  } else {
    // error: unknown signature
  }
}

\n我的意思是,Typescript的创建是为了通过添加一些所谓的“语法糖”来使程序员的生活更轻松,从而获得面向对象设计的优势。那为什么Typescript不能代替程序员做这种令人烦恼的事情呢?例如,可能会像这样:\n

function foo(param1: number): void { 
  // implementation 1 
}; 
function foo(param1: number, param2: string): void {
  // implementation 2 
};
foo(someNumber); // result 1
foo(someNumber, someString); // result 2
foo(someNumber, someNumber); // ts compiler error

\n而这段Typescript代码将被转译为以下Javascript代码:\n

function foo_1(param1) { 
  // implementation 1 
};
function foo_2(param1, param2) { 
  // implementation 2 
}; 
function foo(args) {
  if (args.length === 1 && typeof args[0] === 'number') {
    foo_1(args);
  } else if (args.length === 2 && typeof args[0] === 'number' && typeof args[1] === 'string') {
    foo_2(args);
  } else {
    throw new Error('Invalid signature');
  }
};

\n我没有找到任何原因,解释为什么Typescript不像这样工作。有任何想法吗?

0
0 Comments

为什么TypeScript不以正确的方式支持函数重载?

TypeScript的设计目标之一是通过添加一些所谓的“语法糖”来简化程序员的生活,从而提供面向对象设计的优势。然而,支持函数重载的独立实现并不是TypeScript的设计目标之一。根据TypeScript的设计目标,它不依赖于运行时类型信息。

在TypeScript的存储库中,有很多关于添加函数重载的建议被拒绝。例如,[此链接](https://github.com/Microsoft/TypeScript/issues/3442)。

尽管有人希望TypeScript能够以正确的方式支持函数重载,但目前它并不支持。这可能是因为函数重载会使类型推断变得复杂,增加编译器的复杂性。此外,函数重载的语法可能会使代码更加难以阅读和理解。

虽然TypeScript目前不支持函数重载的正确方式,但仍有一些替代方法来实现类似的功能。一种常见的方法是使用联合类型和类型保护来模拟函数重载。通过使用不同的参数类型来重载函数,并在函数体内使用类型保护来处理不同的情况,可以模拟函数重载的行为。

以下是一个示例代码,演示了如何使用联合类型和类型保护来模拟函数重载:

function foo(bar: string): string;
function foo(bar: number): number;
function foo(bar: string | number): string | number {
  if (typeof bar === 'string') {
    return 'Hello, ' + bar;
  } else {
    return bar * 2;
  }
}
console.log(foo('World')); // Output: Hello, World
console.log(foo(2)); // Output: 4

在上面的代码中,我们定义了一个名为foo的函数,它接受一个参数bar,可以是字符串或数字类型。根据参数的类型,函数体内的逻辑会有所不同。如果参数是字符串类型,函数会返回一个拼接了字符串的结果;如果参数是数字类型,函数会返回参数的两倍。

尽管这种方法可以模拟函数重载,但它仍然有一些限制。例如,它无法处理更复杂的重载情况,如参数数量的不同或参数类型的组合。因此,这种方法可能不适用于所有情况。

,尽管TypeScript当前不支持函数重载的正确方式,但我们可以使用联合类型和类型保护来模拟函数重载的行为。然而,这种方法有一些限制,无法处理所有的重载情况。如果需要更复杂的函数重载功能,可能需要考虑其他的编程语言或工具。

0
0 Comments

为什么TypeScript没有以正确的方式支持函数重载?

如果我们想要在TypeScript中实现真正的函数重载,可以考虑如何实现。可以很容易地让编译器将一组单独的函数合并成一个函数。但是在运行时,这个合并后的函数必须根据参数的数量和类型来确定调用哪个底层函数。参数的数量可以在运行时确定,但是参数的类型在编译后被完全擦除了,所以无法实现这一点。

当检查number类型时,可以输出typeof xxx === 'number',这似乎是显而易见的。但是当检查用户定义的interface时,应该输出什么呢?一种解决方法是要求开发人员为每个函数重载提供一个用户定义的类型保护函数,用于确定参数的类型是否正确。但是现在开发人员需要为每个函数重载指定一对一对的东西,这比当前的TypeScript重载概念更加复杂。

为了好玩,让我们看看如何使用一个期望使用函数和类型保护函数来构建重载函数的库来实现这一点。假设我们使用TypeScript 3.1或更高版本:

interface FunctionAndGuard {
  function: (...args: A) => R,
  argumentsGuard: (args: any[]) => args is A2
};
type AsAcceptableFunctionsAndGuards = { [K in keyof F]:
  F[K] extends FunctionAndGuard ?
  FunctionAndGuard : never
}
type UnionToIntersection =
  (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never
type Lookup = K extends keyof T ? T[K] : never;
type FunctionAndGuardsToOverload =
  Lookup, 'function'>;
function makeOverloads(
  ...functionsAndGuards: F & AsAcceptableFunctionsAndGuards
): FunctionAndGuardsToOverload {
  return ((...args: any[]) =>
    functionsAndGuards.find(fg => fg.argumentsGuard(args))!.function(...args)) as any;
}

`makeOverloads()`函数接受一个可变数量的`FunctionAndGuard`参数,并返回一个单一的重载函数。试试看:

function foo_1(param1: number): void {
  // implementation 1 
};
function foo_2(param1: number, param2: string): void {
  // implementation 2 
};
const foo = makeOverloads({
  function: foo_1,
  argumentsGuard: (args: any[]): args is [number] =>
    args.length === 1 && typeof args[0] === 'number'
}, {
    function: foo_2,
    argumentsGuard: (args: any[]): args is [number, string] =>
      args.length === 2 && typeof args[0] === 'number' && typeof args[1] === 'string'
  }
);
foo(1); // okay
foo(1, "two"); // okay
foo(1, 2); // error

看起来不错!

总结一下:在一般情况下,没有办法在运行时确定参数的类型,这就需要开发人员指定类型保护。因此,你可以通过要求开发人员为每个函数重载指定类型保护来实现重载,或者使用现在的方式,即使用单一实现和多个调用签名。后者更简单。

希望这能给你一些启示。祝你好运!

0