所以,在我的打字稿具有以下枚举:
enum TOKEN { OMG = 'OMG', ZRX = 'ZRX', ... }
enum CONTRACT_ADDRESS { OMG = '0x123...', ZRX = '0x3333.....' ... }
enum PRECISIONS = { OMG = 18, ZRX = 5, ... }
我用他们的泛型类的样子:
class ERC20Tx<T extends TOKEN, P extends PRECISIONS, A extends CONTRACT_ADDRESS>{ ... }
然后,命名的目的,我说:
class OMG extends ERC20Tx<TOKEN.OMG, PRECISIONS.OMG, CONTRACT_ADDRESS.OMG> {}
class ZRX extends ERC20Tx<TOKEN.ZRX, PRECISIONS.ZRX, CONTRACT_ADDRESS.ZRX> {}
最后,我有课,其任务是ETHTx转换成上述ERC20之一。
class ETH2ERC20<E extends ERC20<T, P, A>, T extends TOKEN, P extends PRECISIONS, A extends CONTRACT_ADDRESS> { ... }
终于,我的问题是,是否有可能简化ETH2ERC20的类型,因为我更愿意称他们为这样的:
const omgStream = new ETH2ERC20<OMG>({ ... });
const zrxStream = new ETH2ERC20<ZRX>({ ... });
代替:
const omgStream = new ETHERC20<OMG, TOKEN.OMG, PRECISION.OMG, CONTRACT_ADDRESS.OMG>(); // ....
是否有可能?因为OMG / ZRX / ...就已经包含了什么是T,P的信息,A?
这只要你的类structurally取决于类型当然是可能的T
,P
,A
等(例如,类可以有类型的属性T
,P
和A
)。如果你不这样做,编译器会be unable to infer the type parameters from your classes。
无论如何,让我们来看看你的类型。首先进行的简化,我建议仅仅是使用对应于你有三个K
对象的键单一类型的参数enum
。由于这些都是相同的密钥,并且由于它并不像你混合和匹配类型(例如,你不会做class OMX extends ERC20Tx<TOKEN.OMG, PRECISIONS.OMG, CONTRACT_ADDRESS.ZRX> {}
),额外的类型参数是多余的:
class ERC20TxSimpler<K extends keyof typeof TOKEN>{
k!: K;
t!: (typeof TOKEN)[K];
p!: (typeof PRECISIONS)[K];
a!: (typeof CONTRACT_ADDRESS)[K];
}
class OMGSimpler extends ERC20TxSimpler<'OMG'> { }
class ZRXSimpler extends ERC20TxSimpler<'ZRX'> { }
请注意,我创建的属性t
,p
和a
对应于旧ERC20TxSimpler<K>
,T
和P
类型参数的适当类型的A
。我还做了一个k
属性,其类型为K
。这不是绝对必要的,只要你有这些类型的其他一些固体结构的依赖,但我会在什么样的来使用这些属性。
第二个简化是使用编译器的能力来推断和或look up类型,让你离开过你的ETH2ERC20
类冗余类型参数:
class ETH2ERC20Simpler<E extends ERC20TxSimpler<keyof typeof TOKEN>> {
e!: E;
t!: E['t'];
p!: E['p'];
a!: E['a'];
}
请注意,这个类也有属性,展示如何计算出对应于旧类型参数的类型。该类型ETH2ERC20Simpler<E>.p
的,例如,是E['p']
,这意味着它会查找任何你传递作为p
的E
财产。例如:
declare const eth2erc20omg: ETH2ERC20Simpler<OMGSimpler>;
eth2erc20omg.e; //OMGSimpler
eth2erc20omg.a; //CONTACT_ADDRESS.OMG
eth2erc20omg.p; //PRECISIONS.OMG
eth2erc20omg.t; //TOKEN.OMG
仰望性质是不拔类型进行其他类型的唯一途径。在一般情况下,只要结构性的依赖是足够简单,你可以使用conditional type inference拉出这些类型:
type KfromE<E> = [E] extends [ERC20TxSimpler<infer K>] ? K : never;
class ETH2ERC20Simpler<E extends ERC20TxSimpler<keyof typeof TOKEN>> {
e!: E;
k!: KfromE<E>;
t!: (typeof TOKEN)[KfromE<E>];
p!: (typeof PRECISIONS)[KfromE<E>];
a!: (typeof CONTRACT_ADDRESS)[KfromE<E>];
}
这与前面的代码相同的效果,但它在有条件的类型依赖于infer
。要么应该工作。我宁愿自己查找,因为它们不依赖于编译器“神奇”为多,但它是由您决定。
希望帮助;祝好运!
我相信你可以使用关键字infer
做到这一点:
type InferToken<E> = E extends ERC20Tx<infer G, any, any> ? G : never;
type InferPrecision<E> = E extends ERC20Tx<any, infer G, any> ? G : never;
type InferAddress<E> = E extends ERC20Tx<any, any, infer G> ? G : never;
class ETH2ERC20<E extends ERC20Tx<TOKEN, PRECISIONS, CONTRACT_ADDRESS>, T = InferToken<E>, P = InferPrecision<E>, A = InferAddress<E>> { }
// Has type: ETH2ERC20<ERC20Tx<TOKEN.OMG, PRECISIONS.OMG, CONTRACT_ADDRESS.OMG>, TOKEN.OMG, PRECISIONS.OMG, CONTRACT_ADDRESS.OMG>
const a = new ETH2ERC20<ERC20Tx<TOKEN.OMG, PRECISIONS.OMG, CONTRACT_ADDRESS.OMG>>();
// or
const b = new ETH2ERC20<OMG>();