![](/img/trans.png)
[英]How to know if the email has already been registered in firebase authentication, javascript?
[英]Typescript Trait Implementation: how to let generic know it has been already been extended?
嗨,也許標題是不對的,但我已經嘗試用我有限的知識來指出我遇到的問題。 如果不對,請幫助編輯它。
我正在嘗試創建一些特征函數來鏡像一個類。 更像是PHP特質。
我這樣做的原因是
嘗試使用相同的設置而不寫兩次。
像這里的minx功能https://www.typescriptlang.org/docs/handbook/mixins.html
實現類要求您首先將目標類聲明為undefined或etc。
2。 不是父母和孩子。 它沒有擴展。
編譯后該功能運行良好,但我不知道如何解決TS錯誤。
TS無法解析B已經擁有A的方法和屬性。
代碼如下。
export const trait = ( Orig : any ) : ClassDecorator =>
< T extends Function >( Tgt : T ) : void => {
let _stats =
Object
.getOwnPropertyNames( Orig )
.filter( prop =>
prop != 'length'
&& prop != 'prototype'
&& prop != 'name'
)
;
for( let _stat of _stats )
Object.defineProperty(
Tgt
, _stat
, Object.getOwnPropertyDescriptor( Orig , _stat ) || {}
)
let _insts =
Object
.getOwnPropertyNames( Orig.prototype )
.filter( prop =>
prop != 'constructor'
)
;
for( let _inst of _insts )
Object.defineProperty(
Tgt.prototype
, _inst
, Object.getOwnPropertyDescriptor( Orig.prototype , _inst ) || {}
)
} ;
class A {
propA = 1 ;
static propB = 2 ;
} ;
trait( A )
class B {
PropC = 3 ;
static propD = 4 ;
} ;
console.log( B.propA ) ;
console.log( new B().PropB ) ;
我收到的錯誤就像
Property 'propA' does not exist on type 'typeof B'. Did you mean 'propD'?
[更新]
感謝@T'的幫助,經過長時間的嘗試,我發現了如何做到這一點。
首先,在類型檢查器下方。 合並靜態和原型。
type mir< C , O > =
{
new( ... agrs : any ) :
Inst< C >
& { [ I in keyof InstanceType< O > ] ?: InstanceType< O >[ I ] ; }
}
& C
& { [ I in keyof O ] ?: O[ I ] ; }
;
其次,這是實現它的方法。
class orig {}
@trait( orig )
class tgt {}
// js will work here but ts error will ocurr.
// therefore extend the types as well.
const Tgt : mir< tgt , orig > = tgt ;
所以特性將在JS中工作,如果你使用TS需要寫更多的配置類型。
我不會談論實現,它對我不起作用,但問題是如何讓類型進行鍛煉。
裝飾器不能改變類的類型,這是設計的。 但是,您可以使用函數來轉換類的類型。
要合並類屬性,我們可以使用一些條件和映射類型魔術。 解決方案:
type Constructor = new (...a: any[]) => any;
type Merge<TTrait extends Constructor, TTarget extends Constructor> =
(new(...a: ConstructorParameters<TTarget>) => InstanceType<TTrait> & InstanceType<TTarget>) & Pick<TTarget, keyof TTarget> & Pick<TTrait, keyof TTrait>
const trait = <TTrait extends Constructor>(Orig: TTrait) =>
<TTarget extends Constructor>(Tgt: TTarget) : Merge<TTrait, TTarget> => {
// perform patching
return Tgt as any; // assertion required
}
class A {
propA = 1;
static propB = 2;
};
const B = trait(A)(class {
PropC = 3;
static propD = 4;
});
console.log(B.propB);
console.log(B.propD);
console.log(new B().PropC);
console.log(new B().propA);
class C extends B {
}
一點解釋:
我們需要采用將在TTrait
和TTarget
類型參數中捕獲的兩個類類型並合並它們。 要合並類型,我們需要一個新的構造函數類型,它返回兩個實例類型的交集。 我們可以使用預定義的條件類型InstanceType<T>
來獲取實例類型。 然后我們可以將它們相交以創建新的實例類型: InstanceType<TTrait> & InstanceType<TTarget>
構造函數還需要從TTarget
復制參數。 我們可以使用ConstructorParameters
從目標構造ConstructorParameters
中獲取參數,並使用rest參數中的元組將它們分散回新的構造函數中 。
最后一步是添加每個類的靜態,刪除原始類中的構造函數。 我們可以使用Pick
執行此操作,它將選擇所有命名屬性,但不會選擇構造函數或函數簽名。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.