【问题标题】: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 何时获取签名以及何时失败。

标签: typescript types type-hinting


【解决方案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>
}

【讨论】:

    猜你喜欢
    • 2019-03-20
    • 1970-01-01
    • 2022-11-11
    • 2020-12-28
    • 2019-07-05
    • 2020-03-22
    • 2018-05-02
    • 2016-08-26
    • 2021-10-27
    相关资源
    最近更新 更多