首页 > 解决方案 > 为什么在循环依赖中,命名函数的处理方式与箭头函数不同?

问题描述

我正在尝试在 TypeScript 中推出自己的依赖注入机制,但遇到了一个有趣的问题。在声明我的依赖项时,我必须使用命名函数而不是箭头函数(通常是我的默认函数),否则我会收到循环声明错误。

以下是构成我的依赖解析器的一组类型:

type CollectionTemplate = {
    [key: string]: (...args: any) => any
}

type RegistryTemplate = {
    [key: string]: CollectionTemplate
}

type RegistryCollection<R extends RegistryTemplate> = keyof R

type CollectionEntry<C extends CollectionTemplate> = keyof C

type BaseRegistry<R extends RegistryTemplate> = R

type BaseContext<R extends RegistryTemplate> = {
    [C in RegistryCollection<R>]: {
        [E in CollectionEntry<R[C]>]: ReturnType<R[C][E]>
    }
}

type BaseUseDep<R extends RegistryTemplate> =
    <C extends RegistryCollection<R>, E extends CollectionEntry<R[C]>>
        (collection: C, entry: E) => BaseContext<R>[C][E]

现在,当我使用命名函数时,这一切都很好:

type DepRegistry = BaseRegistry<typeof registry>
type DepContext = BaseContext<DepRegistry>
type UseDep = BaseUseDep<DepRegistry>

function greet(deps: UseDep)
{
    return (name: string) =>
    {
        const console = deps('system', 'console')
        console.log(name)
    }
}

function printGreeting(deps: UseDep)
{
    return () =>
    {
        const greet = deps('social', 'greet')
        greet('John')
    }
}

const registry = {
    system: {
        console: () => console,
    },
    social: {
        greet,
        printGreeting,
    }
}

但是,如果我使用箭头函数而不是命名函数声明这些函数,则会出现以下错误:

Type alias 'DepRegistry' circularly references itself. ts(2456)
Type alias 'UseDep' circularly references itself. ts(2456)

为什么是这样?仅仅是因为我将函数分配给变量而不是声明显式函数吗?

编辑:这里是带有命名函数箭头函数的游乐场。

标签: typescriptlambdatypescircular-dependency

解决方案


以下答案部分解释了该问题;它的意思是评论

我认为,命名函数和箭头函数之间存在差异的原因可能是类型签名的lazy vs eager解析。

Anders Hejlsberginterface vs type在此 GitHub 评论中比较了分辨率

诀窍是在接口类型中进行递归反向引用。这是因为接口基类型和接口成员的解析被延迟,而类型别名的解析被急切地执行。

function可以指定 a 的签名,interface { (...params: Params): Return }因此 Typescript 编译器使用惰性解析策略,并且允许递归定义。

我不知道为什么箭头函数被区别对待,但似乎他们的类型签名被热切地评估了。


我经常遵循类似的依赖注册/注入模式,之前遇到过这个问题。从来没有想过用常规功能替换箭头。很高兴知道这是一种可能性。您也可以首先考虑避免循环依赖。

这个问题本身非常违反直觉,同时也非常有趣。


推荐阅读