在 TypeScript 中,如何使用方法断言类变量的值?

Sup*_*ero 4 typescript

我想要一个方法来告诉打字稿我的客户端已初始化(不再为空)。基本上,我能够做到这一点,但方式似乎不必要地冗长。这是我当前的实现:

export abstract class CacheService {
    storeClient: ICacheStoreInterface | null = null

    protected constructor(storeClientGetter: () => Promise<ICacheStoreInterface>) {
        this.logger = Container.get(Logger)
        void this.initialise(storeClientGetter)
    }

    private checkInitialisation(client: ICacheStoreInterface | null): asserts client is ICacheStoreInterface {
        if (!this.storeClient) {
            throw new Error('Attempting to access cache before initialisation')
        }
    }

    private async initialise(storeClientGetter: () => Promise<ICacheStoreInterface>) {
        try {
            this.storeClient = await storeClientGetter()
        } catch (error) {
            this.logger.error(`Error initialising cache service:\n${error}`)
        }
    }

    public async set(key: storeKey, value: any) {
        this.checkInitialisation(this.storeClient)
        await this.storeClient.set(key, value)
    }

    public async get(key: storeKey) {
        this.checkInitialisation(this.storeClient)

        return this.storeClient.get(key)
    }
}

export interface ICacheStoreInterface {
    get(key: storeKey): Promise<any>
    set(key: storeKey, value: any): Promise<void>
}

export type storeKey = number | string | symbol
Run Code Online (Sandbox Code Playgroud)

TS 游乐场链接

我想要做的是实现相同的结果,但不必显式地将 this.storeClient 传递给 checkInitialization 方法。看起来这是可能的,因为方法和父函数都可以访问变量,所以也许它们可以以某种方式共享类型数据?本质上,我正在寻找类似的东西asserts this.storeClient is ICacheStoreInterface,尽管这个确切的例子行不通。这是可能的还是我将不得不忍受这个“毫无意义”的变量带来的轻微不便?

jca*_*alz 6

不直接支持形式的类型谓词arg.prop is Type,也不直接支持形式的断言谓词asserts arg.prop is Type。请参阅microsoft/TypeScript#11117了解此类功能(至少是类型谓词)的开放功能请求。它被列为“等待更多反馈”,因此您可能想要去那里,给它一个 ,并描述您的用例(我想断言谓词在那里可能有点偏离主题;不确定)......但现在它是不是语言的一部分。

虽然你不能写asserts this.storeClient is ICacheStoreInterface,但你可以asserts this is {storeClient: ICacheStoreInterface},这是相似的。或者可能asserts this is this & {storeClient: ICacheStoreInterface},取决于编译器是否要求谓词是严格缩小的(似乎不需要,但也许在某些情况下它很重要)。对于您的示例,无论如何,它似乎表现得如预期:

private checkInitialization(): asserts this is { storeClient: ICacheStoreInterface } {
    if (!this.storeClient) {
        throw new Error('Attempting to access cache before initialisation')
    }
}

public async get(key: storeKey) {
    this.checkInitialization()
    // this is now this & { storeClient: ICacheStoreInterface; }
    return this.storeClient.get(key) // okay
}
Run Code Online (Sandbox Code Playgroud)

此类属性类型防护仅在您要缩小的属性不适用时才起作用private;如果该属性privatethis缩小为,never因为具有属性的对象private不能分配给具有public相同键的属性的对象。这就是这种方法的局限性。

Playground 代码链接