有没有办法用可选参数缩小打字稿重载的范围?

问题描述

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

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,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,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 来做这件事,所以我必须用打字稿来做这件事似乎是错误的。

TS Playground Link

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

解决方法

您可以通过为参数引入数组类型来实现完全类型化:

toHaveLastReturnedWith

然后将其用作 discriminating union,其中数组长度是 TypeScript 将用于确定我们正在处理的联合的替代项中的哪些判别字段:

type Args = [rgb: RgbColor] | [r: number,g: number,b: number]

TypeScript playground

,

问题是,变量 public class TransactionsCountTest extends BaseTest { public static void main(String[] args) { int i = 1; DatabaseHelper databaseHelper = DatabaseHelper.getInstance(); HashMap<String,String> users = databaseHelper.getTransactionUserIdsWithCount(); TransactionsCountTest transactionsCountTest = new TransactionsCountTest(); for (String user : users.keySet()) { System.out.println(i); transactionsCountTest.compareStatementsCount(user,users.get(user)); i++; } } private void compareStatementsCount(String user,String DbCount) { int dbCount = Integer.parseInt(DbCount); int vendorCount = 0; try { logger.info("Checking " + user); List<SalesItemShort> venTransactions = Helpers.getCollectionFromResponse(salesDataSteps.getUserSalesData(user).getBody(),SalesItemShort[].class); vendorCount = venTransactions.size(); assertEquals(vendorCount,dbCount); } catch (AssertionError e) { if (e.getMessage().contains("was NOT")) { logger.info("Request timeout for user " + user); } else { logger.info("Data for user " + user + " is incorrect"); logger.info("Transactions in DB " + dbCount); logger.info("Transactions in Vendor " + vendorCount); } } } g 将始终属于 b 类型,它们不能在不声明新变量的情况下永久重新分配。

您有 4 个选择:

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

经过更多的谷歌搜索、阅读其他 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:工具错误。等待修复。