在typescript專案中解決cycle依賴的一種方案

myskies發表於2023-04-04

在typescript中,如果你不小心建立了類似以下兩個檔案,那麼則會發生一個依賴警告。在個別的時候,還可能導致build失敗的情況。

import Foo from "foo";
export class Bar {
    private foo: Foo;
    barFun() {
        this.foo.xxx(this);
    }
}
import Bar from "bar";
export class Foo {
    xxx(bar: Bar) {
        console.log("xxx");
    }
}

此時由於 bar 中 import 了 foo, 然後 foo 又import 了 bar,所以產生了cycle.

bar -> foo -> bar -> foo -> bar -> ...

此時我們則可引入 interface 來解決這個迴圈的依賴.

引入interface

export interface BarInterface {
    barFun(): void;
}
import Foo from "foo";
export class Bar {
    private foo: Foo;
    barFun() {
        this.foo.xxx(this);
    }
}
import BarInterface from "bar-interface";
export class Foo {
    xxx(bar: BarInterface) {
        console.log("xxx");
    }
}

此時,在進行引入時,則不會發生clcle了:

  1. 引入 BarInterface: bar.interface -> end
  2. 引入 Bar: bar -> foo -> bar.interface -> end
  3. 引入 Foo: foo -> bar.interface -> end

適用場景

該方法適用於以下場景:我們需要對歷史的專案進行維護,但這個專案擁有多個版本,所以我們需要減少對原始碼的入侵量。同時呢,我們在維護的過程中,還需要呼叫原始碼中的相應功能。重要的是,還不能造成cycle。

比如:

export class FooService {
    fun1() {
    }
    fun2() {
    }
}

現在我們需要對fun1()進行功能上的補充,在補充其功能時,還需要呼叫fun2(),則建立了以下兩個檔案:

import FooService from 'foo.service';
import FooFixService from 'foo-fix.service';
export class FooSerivceHook {
    private fooFixService = new FooFixService();
    fun2(fooService: FooService) {
        this.fooFixService.foo(fooService);
    }
}
import FooService from 'foo.service';
export class FooFixService {
    foo(fooService: FooService) {
        // 一些功能性的程式碼補充,並在補充過程中呼叫了原來的fun2()方法
        this.fooService.fun2();
    }
}

最後我們改寫原始碼:

import FooSerivceHook from 'foo-service.hook';
export class FooService {
    private fooSerivceHook = new FooSerivceHook();
    fun1() {
    }
    fun2() {
        this.fooServiceHook.fun2();
    }
}

上述程式碼功能上沒有問題,但卻引發了cycle的問題:

FooService -> FooSerivceHook - > FooService -> ...

此時我們則可以使用本文的方法建立 interface 來規避 cycle 的產生,同時由於在原 FooService 上宣告瞭介面實現,在進行其它版本的程式碼修正的快速遷移程式碼的過程中,也可以快速的發現遷移過程中的問題。

相關文章