簡體   English   中英

如何顯式注釋 TypeScript 混合工廠函數的返回類型?

[英]How to explicitly annotate the return type of a TypeScript mixin factory function?

鑒於此處描述的示例 TypeScript mixin 模式:

type Constructor = new (...args: any[]) => {};
 
// This mixin adds a scale property, with getters and setters
// for changing it with an encapsulated private property:
 
function Scale<TBase extends Constructor>(Base: TBase) {
  return class Scaling extends Base {
    // Mixins may not declare private/protected properties
    // however, you can use ES2020 private fields
    _scale = 1;
 
    setScale(scale: number) {
      this._scale = scale;
    }
 
    get scale(): number {
      return this._scale;
    }
  };
}

我們將如何顯式注釋Scale函數的返回類型? 也就是說,填寫???

function Scale<TBase extends Constructor>(Base: TBase): ??? { 
  ...

您不需要為Scale函數聲明顯式返回類型,因為 TypeScript 足夠聰明,可以推斷返回類型。 將鼠標懸停在Scale ,您將看到返回類型為

{
    new (...args: any[]): Scaling;
    prototype: Scale<any>.Scaling;
} & TBase

此外,如果您想為Scale使用顯式返回類型,您應該在Scale函數之外聲明Scaling (內部類)。 像這樣:

 class Scaling extends Base {

    _scale = 1;
 
    setScale(scale: number) {
      this._scale = scale;
    }
 
    get scale(): number {
      return this._scale;
    }
  }

function Scale<TBase extends Constructor>(Base: TBase) {
  return Scaling
}

但是Base應該是靜態的。

這意味着我們應該創建Mixin函數,就像在docs - Alternative Pattern 中一樣

// credits goes to credits goes to https://stackoverflow.com/a/50375286
type UnionToIntersection<U> =
    (U extends any ? (k: U) => void : never) extends (
        k: infer I
    ) => void
    ? I
    : never;

type ClassType = new (...args: any[]) => any;

function Mixin<T extends ClassType, R extends T[]>(...classRefs: [...R]):
    new (...args: any[]) => UnionToIntersection<InstanceType<[...R][number]>> {
    return merge(class { }, ...classRefs);
}

function merge(derived: ClassType, ...classRefs: ClassType[]) {
    classRefs.forEach(classRef => {
        Object.getOwnPropertyNames(classRef.prototype).forEach(name => {
            // you can get rid of type casting in this way
            const descriptor = Object.getOwnPropertyDescriptor(classRef.prototype, name)
            if (name !== 'constructor' && descriptor) {
                Object.defineProperty(
                    derived.prototype,
                    name,
                    descriptor
                );
            }
        });
    });

    return derived;
}

class Foo {
    tag = 'foo'
}

class Scaling extends Mixin(Foo) {

    _scale = 1;

    setScale(scale: number) {
        this._scale = scale;
    }

    get scale(): number {
        return this._scale;
    }
}

const result = new Scaling();

result.tag // string
result.scale // number

您可以在medium我的博客找到我的文章分步說明。

UnionToIntersection - 創建聯合類型的交集。 你可以在這個答案中找到完整的解釋

ClassType - 與您的Constructor幾乎相同的類型。 它是任何類構造函數的類型。

Mixin - 借助可變元組類型推斷參數中提供的每個類構造函數,並將它們的所有實例合並為一個對象UnionToIntersection<InstanceType<[...R][number]>>

`[...R][number]` - takes a union of all provided class intstances
`InstanceType<[...R][number]>>` - replace every class constructor in the union 
                                  with class instance accordingly
`UnionToIntersection<InstanceType<[...R][number]>>` - merges all class instances

merge - 與文檔中的applyMixins相同

更新

由於Scaling是在函數內部定義的,因此不可能添加包含Scaling顯式返回類型,因為它還不存在於作用域中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM