是有可能推断出类型参数的类型?

问题描述 投票:2回答:2

所以,在我的打字稿具有以下枚举:

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?

typescript generics
2个回答
2
投票

这只要你的类structurally取决于类型当然是可能的TPA等(例如,类可以有类型的属性TPA)。如果你不这样做,编译器会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'> { }

请注意,我创建的属性tpa对应于旧ERC20TxSimpler<K>TP类型参数的适当类型的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'],这意味着它会查找任何你传递作为pE财产。例如:

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。要么应该工作。我宁愿自己查找,因为它们不依赖于编译器“神奇”为多,但它是由您决定。

希望帮助;祝好运!


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>();
© www.soinside.com 2019 - 2024. All rights reserved.