打字稿:函数参数的类型辅助

Posted

技术标签:

【中文标题】打字稿:函数参数的类型辅助【英文标题】:Typescript: type assist for function argument 【发布时间】:2022-01-12 19:52:17 【问题描述】:

我已经编写了一个小库,现在我正在尝试通过创建自定义 d.ts 文件来为其添加类型支持。

举个例子(我的库叫做layerCompose):

const C = layerCompose(
  
     _($)  /* function body */ ,
     execute($)  /* function body */ 
  
)
const c = C()
c._()

您会注意到_execute 函数都带有一个参数$。 此参数(在我们的示例中)是具有_execute 属性的对象(类似于类中的this

所以,我想为这个$ 参数添加类型支持。通过实验,我发现在我的 d.ts 文件中包含此定义可以在 _ 函数中提供类型支持。

export function layerCompose<
  T extends [
    A extends  
      ? 
        _($: test: () => void)
       
      : never
  ]
  , A
>(...layers: T): lcConstructor<Spread<T>>

也就是说Webstorm可以看到_函数中的$参数的类型是test: () =&gt; void

显然,这不是我想要的。但是,将签名更改为(我认为合适的)

export function layerCompose<
  T extends [
    A extends  
      ?  
        [K in keyof A]: ($: test: () => void) => any 
       
      : never
  ]
  , A
>(...layers: T): lcConstructor<Spread<T>>

Webstorm 失去了判断$ 是具有_execute 属性的对象的能力。


编辑:Included an example on typescript playground。它缺少返回类型(快速设置它并非易事),但可以深入了解layerCompose 的大致作用。


编辑 2:

进一步玩,已简化为 1 个参数场景,这是可行的:

export function layerCompose<L1>(l1: _: ($: test: () => void) => void & L1): void

但事实并非如此:

export function layerCompose<L1>(l1: [K in keyof L1]: ($: test: () => void) => void & L1): void

【问题讨论】:

A 是如何被解析的,为什么在函数签名中没有用到它?您应该为您的问题编写一个完全可重现的示例。 typescriptlang.org/play 将受到欢迎 您提供的用于键入layerCompose 的示例始终会生成T = never。你确定他们被使用了吗? Webstorm 可能无法正确识别您的声明文件。 @GuerricP 示例已添加。 @Olian04 我一直在努力确保传播对我的 d.ts 文件的更新。我可以看到 Webstorm 何时获取签名以及何时失败。 【参考方案1】:

这就是你要找的吗?

export function layerCompose(...layers: Layer[]): lcConstructor<Spread<T>>;

由于您既没有定义lcConstructorSpread,所以我无法真正猜测layerCompose 的返回类型应该是什么。因此,出于此答案的目的,这些类型已替换为身份类型。

// See playground below
type ComposedLayer = 
  _(): void;
  execute(): void;

type Layer = 
  _(v: Layer): void;
  execute(v: Layer): void;


/* dummy type */ type lcConstructor<T> = ComposedLayer;
/* dummy type */ type Spread<T> = T;

declare function layerCompose(...layers: Layer[]): lcConstructor<Spread<Layer>>;

const C = layerCompose(
  
     _($) ,
     execute($) 
       $._(
         _($) ,
         execute($) 
       )
     
  
);

C._();

playground

【讨论】:

看看我提供的游乐场示例。麻烦的是我提前不知道Layer的形状。【参考方案2】:

根据个人经验,先找个泛型类型,避免循环依赖。请检查以下定义。

type Layer<K extends string> = Partial<Record<K, ($: Record<K, Function>) => void>>

function layerCompose<K extends string>(...layers: Layer<K>[]): Record<K, Function>
  // ignore how do you implement to match types
  return  as Record<K, Function>

【讨论】:

以上是关于打字稿:函数参数的类型辅助的主要内容,如果未能解决你的问题,请参考以下文章

打字稿泛型:从函数参数的类型推断类型?

如果参数为空,则打字稿函数返回类型为空

函数的打字稿联合/交集类型

基于可选参数存在而不使用函数重载的打字稿函数返回类型

打字稿递归函数组合

获取打字稿默认/初始参数类型以扩展它