使用装饰器函数导致循环引用类型错误

Use of decorator function causes circular reference type errors

我的代码工作得很好,直到我尝试用装饰器包装一个函数定义(“装饰器”我只是指一个高阶函数,它将一个函数作为参数,return 另一个函数,我不是在谈论即将到来的装饰器语法)。当我使用这个装饰器时,我得到错误 Type alias 'Thing' circularly references itself。为什么会这样?

下面是损坏的代码示例(这是一个极其简化的版本,试图简单地展示我 运行 遇到的问题)。

const decorate = (fn: () => boolean) => fn

const thing = {
    fn: decorate(() => {
        type Thing = typeof thing
        const thing_: Thing = thing
        return 'fn' in thing_
    })
}

将其与下面的代码片段进行比较,它工作得很好。我只是删除了对 decorate 的调用(在这个简化示例中这只是一个恒等函数)。

const decorate = (fn: () => boolean) => fn

const thing = {
    fn: () => {
        type Thing = typeof thing
        const thing_: Thing = thing
        return 'fn' in thing_
    }
}

我什至可以使用我的错误示​​例并用以下通用函数替换 decorate 函数,它会神奇地开始工作,即使这两个定义在它们的特定方式上应该是功能等价的'正在使用中。

const decorate = <T>(fn: T): T => fn

更新:对于任何感兴趣的人,以下是我最终解决问题的方法

我必须明确地告诉 TypeScript 我的函数的类型是什么,所以我把它放在一个 IFEE 中并将它分配给一个具有声明类型的变量,如下所示:

const decorate = (fn: () => boolean) => fn

const thing = {
    fn: (() => {
        type MyFnType = () => boolean
        const fn: MyFnType = decorate(() => {
            type Thing = typeof thing
            const thing_: Thing = thing
            return 'fn' in thing_
        })
        return fn
    })()
}

它不是很漂亮,但它解决了这个问题。

(请注意,这不是我自己问题的答案,因为我的问题是问为什么我必须做这样的解决方法,我不一定要问如何做)。

这样写吧

const decorate = (fn: () => boolean) => fn

const t = () => {
        type Thing = typeof thing
        const thing_: Thing = thing
        return 'fn' in thing_
    };

现在如果你写

const thing = {
    fn: decorate(t)
}

由于这涉及使用 t 作为参数调用 decorate,因此编译器 需要 t 可以分配给 ()=>boolean,然后才能继续推断 thing 的类型。所以它必须在推断出thing的类型之前检查t,造成循环引用。即在这种情况下,thing 的类型对 t 很重要,t 的类型对 thing.

也很重要

相比之下你写

const thing = {
    fn: t
}

t 应该是什么类型没有要求。编译器可以继续推断 thing 的类型,只需将 fn 的类型推断为 t 恰好是什么,而不关心它实际是什么。因此无需预先输入 check t 。所以在这种情况下,thing 的类型对 t 很重要,但 t 的类型对 thing.

无关紧要

我最后在 TypeScript 存储库上询问了这个问题(请随意看一看 over here。听起来 TypeScript 无法自动确定我的示例代码片段中的类型的原因可以简单地归结为事实上,这样做需要完全重写很多 TypeScript 编译器,并增加很多复杂性,因为他们认为不需要足够的东西来保证这种重写和增加的复杂性,这当然是可以理解的.

随时看link直接对话。