打字稿:使用特定的扩展接口来满足通用的“扩展”类型参数?

Posted

技术标签:

【中文标题】打字稿:使用特定的扩展接口来满足通用的“扩展”类型参数?【英文标题】:Typescript: use specific extended interface to satisfy generic "extends" type argument? 【发布时间】:2020-10-12 12:45:08 【问题描述】:

这是一个小代码示例(旁注:我正在运行 Typescript v3.8.3):

interface IOptions<T> 
  arg: T;


interface IExtraOptions extends IOptions<number> 
  arg2: string;


type Func = <T, OptionsT extends IOptions<T>>(options: OptionsT) => T;

const f: Func = (options: IExtraOptions): number => 
  return options.arg2 === 'dev' ? 0 : options.arg;
;

我希望这会起作用,因为IExtraOptions 扩展了IOptions 并因此满足OptionsT extends IOptions&lt;T&gt; 约束,但我得到:

类型“OptionsT”不可分配给类型“IExtraOptions”。

“IOptions”类型中缺少属性“arg2”,但在“IExtraOptions”类型中是必需的。ts(2322)

完全删除OptionsT 参数并仅使用IOptions&lt;T&gt; 作为“选项”的类型参数会产生相同的错误。用非默认类型替换“数字”也不能解决它。有谁知道我做错了什么?

【问题讨论】:

【参考方案1】:

如果你有一个泛型函数,函数的泛型类型参数是由调用者决定的,而不是让实现固定为一些任意类型。例如,给定您的示例,此调用将是有效的 f&lt;boolean, IOptions&lt;boolean&gt;&gt;( arg: true ),并且您指定的实现不会返回满足这些类型参数的对象。

结论是,如果你有一个泛型函数,通常只有一个泛型函数才能满足实现(尽管使用非常松散的类型,如anyneverunknown 也可能有效)。

如果你想创建专门的函数,不要使用泛型函数,使用恰好是函数的泛型类型:


type Func <T, OptionsT extends IOptions<T>> =(options: OptionsT) => T;

const f: Func<number, IExtraOptions> = (options ) => 
  return options.arg2 === 'dev' ? 0 : options.arg;
;

Playground Link

您还可以从TOptions 派生T 以简化一些事情:


type Func <OptionsT extends IOptions<any>> =(options: OptionsT) => OptionsT['arg'];

const f: Func<IExtraOptions> = (options ) => 
  return options.arg2 === 'dev' ? 0 : options.arg;
;

Playground Link

【讨论】:

谢谢——泛型类型和泛型函数之间的区别正是我所需要的。感谢您的帮助。

以上是关于打字稿:使用特定的扩展接口来满足通用的“扩展”类型参数?的主要内容,如果未能解决你的问题,请参考以下文章

扩展排他联合的打字稿通用参数

打字稿通用和扩展

Typescript 扩展通用接口

是否可以仅为打字稿上的特定类型扩展 Array.prototype?

打字稿扩展了两个像类型一样的接口?

使用静态方法的打字稿继承