所以,在我的打字稿中有以下枚举:
import { Client, Configuration } from "bugsnag-react-native";
class CrashReporter {
attach() {
const configuration = new Configuration();
configuration.appVersion = "1.4.5";
configuration.apiKey = "0096f**acb8**c76e**ecf6e**a2";
this.bugsnag = new Client(configuration);
}
setCurrentUser(userName, userID, userEmail) {
this.bugsnag.setUser(userID, userName, userEmail);
}
notify(error) {
this.bugsnag.notify(new Error(error));
}
}
export default new CrashReporter();
我在如下所示的通用类中使用了它们:
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>{ ... }
最后,我有一堂课,其任务是将ETHTx转换为上述ERC20之一。
class OMG extends ERC20Tx<TOKEN.OMG, PRECISIONS.OMG, CONTRACT_ADDRESS.OMG> {}
class ZRX extends ERC20Tx<TOKEN.ZRX, PRECISIONS.ZRX, CONTRACT_ADDRESS.ZRX> {}
最后,我的问题是,是否可以简化ETH2ERC20的类型,因为我更喜欢这样称呼他们:
class ETH2ERC20<E extends ERC20<T, P, A>, T extends TOKEN, P extends PRECISIONS, A extends CONTRACT_ADDRESS> { ... }
代替:
const omgStream = new ETH2ERC20<OMG>({ ... });
const zrxStream = new ETH2ERC20<ZRX>({ ... });
有可能吗?因为OMG / ZRX / ...已经包含了信息T,P,A?
答案 0 :(得分:2)
只要您的类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
1}}和P
类型参数。我还制作了一个A
类型的k
属性。只要您对这些类型还有其他牢固的结构依赖性,就不必严格要求这样做,但是我将在以后使用这些属性。
第二个简化是利用编译器的能力来推断和(或)look up类型,以允许您省去K
类中的冗余类型参数:
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
查找属性并不是将类型拉出其他类型的唯一方法。通常,只要结构上的依赖关系足够简单,就可以使用conditional type inference提取以下类型:
declare const eth2erc20omg: ETH2ERC20Simpler<OMGSimpler>;
eth2erc20omg.e; //OMGSimpler
eth2erc20omg.a; //CONTACT_ADDRESS.OMG
eth2erc20omg.p; //PRECISIONS.OMG
eth2erc20omg.t; //TOKEN.OMG
这与前面的代码具有相同的效果,但是它依赖于条件类型中的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>];
}
。两者都应该起作用。我本人更喜欢查找,因为它们不太依赖编译器“魔术”,但这取决于您。
希望有所帮助;祝你好运!
答案 1 :(得分:1)
我相信您可以使用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>();