有没有办法通过可选参数来缩小打字稿重载范围?

问题描述 投票:0回答:3

我正在尝试执行以下操作:

interface RgbColor {
  r: number;
  g: number;
  b: number;
}

function rgbToHex(r: RgbColor, g?: undefined, b?: undefined): string
function rgbToHex(r: number, g: number, b: number): string
function rgbToHex(r: number|RgbColor, g?: number, b?: number): string {
  if (r instanceof Object) {
    // must be RgbColor
    g = r.g;
    b = r.b;
    r = r.r;
  }

  // A) r was an RgbColor and we've already set r, g, and b to numbers in the if block
  // B) we're meeting the second overload and r, g, and b are all numbers
  // either way we know they are all numbers now

  let rHex = r.toString(16);
  let gHex = g.toString(16); // ERROR: Object is possibly 'undefined'.
  let bHex = b.toString(16); // ERROR: Object is possibly 'undefined'.

  if (rHex.length == 1) rHex = "0" + rHex;
  if (gHex.length == 1) gHex = "0" + gHex;
  if (bHex.length == 1) bHex = "0" + bHex;

  return "#" + rHex + gHex + bHex;
}

我在

ERROR
注释所指示的行上收到错误。

从 javascript 的角度来看,这个函数很好:

function rgbToHex(r , g, b) {
  if (r instanceof Object) {
    g = r.g; 
    b = r.b; 
    r = r.r;
  }

  let rHex = r.toString(16);
  let gHex = g.toString(16);
  let bHex = b.toString(16);

  if (rHex.length == 1) rHex = "0" + rHex;
  if (gHex.length == 1) gHex = "0" + gHex;
  if (bHex.length == 1) bHex = "0" + bHex;

  return "#" + rHex + gHex + bHex;
}

rgbToHex({ r: 120, g: 50, b: 5 }) // "#783205"
rgbToHex(120, 50, 5) // "#783205"

我的问题是如何设置函数签名,这样就可以正常工作,而无需进行任何转换,也无需在函数体中设置任何冗余变量。即我想避免做

let gVal: number = g || (r as any).g;

另一种选择是将其分成两个函数并让一个函数调用另一个函数;但我不会用 javascript 来做到这一点,所以我必须用 typescript 来做到这一点似乎是错误的。

TS 游乐场链接

抱歉,如果这是重复的。我花了几个小时查看类似的问题,但找不到解决此问题的任何内容。

typescript overloading narrowing
3个回答
4
投票

经过更多谷歌搜索、阅读其他 SO 问题并浏览 typescript github 问题后,看起来这是 typescript 中尚未实现的功能。

在函数外部起作用的重载缩小尚不适用于函数内:

// function definition for swapping between number and string types
function foo(bar: string): number // overload 1
function foo(bar: number): string // overload 2
function foo(bar: number | string): number|string 
{ ... }

const a = foo('string');
a.toPrecision(); // TS knows a is a number, so this has no errors

const b = foo(5);
b.toLowerCase(); // TS knows b is a string, so this has no errors

const c = Math.random() < .5 ? a : b; // TS knows c as string | number

// the actual implementation of an overloaded method does not count as 
// one of the possible overloads, so calling foo with a variable of type (string|number)
// is not valid
const d = foo(c); // error on parameter 'c': No overload matches this call.

所以这一切都在预料之中。但是当我们尝试实现

foo
时,我们发现该方法中没有应用相同的排除逻辑:

function foo(bar: string): number // overload 1
function foo(bar: number): string // overload 2
function foo(bar: number | string): number | string {
  return bar; // this is valid, it clearly should not be
}

看起来打字稿团队还没有在函数内进行代码分析以了解该函数的重载,似乎严格执行了实现的签名。这显然是错误的。

QED:工具错误。等待修复。


0
投票

问题是,变量

g
b
始终是
number | undefined
类型,如果不声明新变量,则无法永久重新分配它们。

您有 4 个选择:

  1. 使用非空断言运算符
    !
    ,这意味着您需要编写
    g.toString(16)
    ,而不是编写
    g!.toString(16)
    ,强制其为
    number
    类型。您也可以通过类型转换来解决它。
  2. 可以拆成多个函数,提取rgb变量,然后返回原来的
    rgbToHex
    函数。
  3. 正如@Oblosys 的回答中提到的,您可以使用联合类型。
  4. 您可以在函数顶部创建一个新对象,在其中填充一个新的
    RgbColor
    对象。

0
投票

让我们尝试实现以下内容。

function f(a: T, b: S);
function f(a: U, b: S, c: V);

function f(a: T | U, b: S, c?: V) { ... }

经过大量无益的错误和测试后,我设法为一个程序编写了以下内容,该程序使用一些参数生成自定义日志消息。

type LogActionWithoutBuff = 'connect' | 'disconnect';
type LogActionWithBuff = 'receive' | 'send';
type LogAction = LogActionWithBuff | LogActionWithoutBuff;

function formatLog(action: LogActionWithoutBuff, host: string): string;
function formatLog(action: LogActionWithBuff, host: string, buff: Buffer): string;

function formatLog(action: LogAction, host: string, buff?: Buffer): string { ... }

我多次尝试做同样的事情(根本不引用buff),但它现在才起作用。我不明白为什么,也许是编译器的问题。

© www.soinside.com 2019 - 2024. All rights reserved.