【问题标题】:Extending another TypeScript function with additional arguments使用附加参数扩展另一个 TypeScript 函数
【发布时间】:2021-09-04 16:30:33
【问题描述】:

是否可以在 TypeScript 中定义一个函数类型并将其参数列表扩展为另一种类型(重载函数类型?)?

假设我有这种类型:

type BaseFunc = (a: string) => Promise<string>

我想用一个附加参数(b: number) 和相同的返回值定义另一种类型。

如果在未来的某个时候BaseType 添加或更改参数,这也应该反映在我的重载函数类型中。

这可能吗?

【问题讨论】:

  • 参数列表的开头还是结尾?一开始是简单的选择。
  • @Titian 虽然我更喜欢开始,但两者都可以。

标签: typescript


【解决方案1】:

您可以将Tuples in rest parameters and spread expressionsconditional typeinference behavior of conditional types 一起使用,从签名中提取参数并重建新的签名。

type BaseFunc = (a: string) => Promise<string>

type BaseWithB  = BaseFunc extends (...a: infer U) => infer R ? (b: number, ...a:U) => R: never;

【讨论】:

  • 感谢您的帮助,尽管正如我在上面所写的那样,我将使用“选项”解决方案,因为它看起来更干净、更灵活。
  • @Thomas 肯定没问题,我同意这是一个更好的设计。我只是在回答你问的具体打字稿问题:)
  • @TitianCernicova-Dragomir 非常感谢您的回答。这正是我所需要的,因为我需要已经存在的 3rd 方库的类型定义。因此无法更改函数签名。
  • @TitianCernicova-Dragomir 谢谢。如果我希望 b 是最后一个参数怎么办? (它给了A rest parameter must be last in a parameter list.ts(1014)
  • @MoshFeu in ts 4.0+ 你可以做type BaseWithB = BaseFunc extends (...a: infer U) =&gt; infer R ? (...a:[...U, number]) =&gt; R: never;
【解决方案2】:

UPD:可以在 TypeScript 中扩展函数的参数。请参阅 Titian 的answer

原始答案:我怀疑可以按照您描述的方式完成。但是,您可以尝试以下方法:

interface BaseOptions {
    a: string;
}
type BaseFunc = (options: BaseOptions) => Promise<string>

interface DerivedOptions implements BaseOptions {
    b: number;
} 
type DerivedFunc = (options: DerivedOptions) => Promise<string>

这种方法的另一个优点是您可以免费获得命名参数。因此,从调用方来说,它比仅使用位置参数调用BaseFuncDerivedFunc 更干净。比较一下:

someFuncA(1, undefined, true);

// vs

someFuncB({nofiles: 1, enableLogging: true});  // and bar: undefined is just omitted

【讨论】:

  • 永远不要怀疑 Typescript ;)。但是您的解决方案可以说比要求的更清洁。
  • 谢谢大家!我也认为这个解决方案更可取。它还允许我在其他场景中构造选项对象。我会被阻止直接使用该类型。将此标记为最佳答案。
【解决方案3】:

您可以使用带参数的传播:

function base(a: number, b: number, c: number): number
function derived(add: string, ...base: Parameters<typeof base>): number

限制是基本参数必须在末尾。

【讨论】:

  • 很好的解决方案! :thumbup:
【解决方案4】:

您可以将任何附加参数设为可选。

class Plant {
  grow(inches: number) {}
}

class Grass extends Plant {
  // adding new optional argument in override
  grow(inches:number, cutOff?: boolean) {}
}

class CrabGrass extends Grass {
  // At this level of overriding, you no longer need it to be optional
  grow(inches:number, cutOff: boolean) {}
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-26
    • 1970-01-01
    • 1970-01-01
    • 2013-07-18
    • 2020-11-01
    • 1970-01-01
    • 2023-02-23
    相关资源
    最近更新 更多