需要使用接口的 属性 指定重载函数的类型

Need to specify type of an overloaded function using property of an interface

我需要使用接口的 属性 指定函数类型(通常需要使用接口定义模块的 API),但是 ts 抱怨 returned 类型,似乎它只考虑了一种类型定义,因为抱怨 return 类型不正确:

export interface DateWrapper {
    isSame(firstDate: DateType, secondDate: DateType): boolean;
    isSame(firstDate: DateType): (secondDate: DateType) => boolean;
}

export const isSame: DateWrapper['isSame'] = (
    firstDate: DateType,
    secondDate?: DateType,
) => {
    if (!secondDate) {
        return (secondDate_: DateType) =>
          areDatesEqueal(firstDate, secondDate_);
    }

    return areDatesEqueal(firstDate, secondDate);
};

这是来自 ts 的错误:

Type 'boolean | ((secondDate_: DateType) => boolean)' is not assignable to type 'boolean'

使用 function declaration 指定重载可以解决问题,但我需要使用接口 .

属性

似乎没有一种干净的方法来为具有不同return类型的箭头函数指定重载。在 SO 上有很多示例,其中 return 类型相同,或者 any 在 returned 值的函数中。鉴于此,这里有三个不太理想的建议,它们在整洁度和类型正确性方面有所不同。

只需使用类型断言。这里的缺点是,如果 DateWrapper.isSame 的定义发生变化,则会引入错误。一般来说,如果可以的话,最好避免类型断言。

export const isSame = ((firstDate: DateType, secondDate?: DateType) => 
  (secondDate == null) 
    ? (secondDate_: DateType) => areDatesEqueal(firstDate, secondDate_)
    : areDatesEqueal(firstDate, secondDate)
) as DateWrapper['isSame'];

另一种方法是声明重载函数并将其分配给变量。与第一个解决方案不同,如果 DateWrapper.isSame 的定义发生变化,那么在这些函数被重构以匹配之前,您将无法构建。缺点是这个函数存在于某些范围内,可能会造成混淆。

function isSameFn(firstDate: DateType, secondDate: DateType): boolean;
function isSameFn(firstDate: DateType): (secondDate: DateType) => boolean;
function isSameFn(firstDate: DateType, secondDate?: DateType) {
  return (secondDate == null) 
    ? (secondDate_: DateType) => areDatesEqueal(firstDate, secondDate_)
    : areDatesEqueal(firstDate, secondDate);
}
export const isSame: DateWrapper['isSame'] = isSameFn;

两个避免污染一些范围,你可以将函数包装在一个自动执行的函数中,returns isSame 函数。虽然这是最丑陋的,但它没有任何先前解决方案的问题。

export const isSame: DateWrapper['isSame'] = (() => {
  function isSameFn(firstDate: DateType, secondDate: DateType): boolean
  function isSameFn(firstDate: DateType): (secondDate: DateType) => boolean
  function isSameFn(firstDate: DateType, secondDate?: DateType) {
    return (secondDate == null) 
      ? (secondDate_: DateType) => areDatesEqueal(firstDate, secondDate_)
      : areDatesEqueal(firstDate, secondDate);
  }
  return isSameFn;
})();

下面的解决方案涵盖了我的案例,也许对其他人有用:

export interface DateWrapper {
   isSame: typeof isSame;
}

export function isSame (firstDate: DateType, secondDate: DateType): boolean
export function isSame (firstDate: DateType): (secondDate: DateType) => boolean;
export function isSame (firstDate: DateType, secondDate?: DateType) {
    if (!secondDate) {
        return (secondDate_: DateType) => areDatesEqueal(firstDate, secondDate_);
    }

    return areDatesEqueal(firstDate, secondDate);
};