从对象动态创建类型

时间:2018-08-30 08:43:34

标签: typescript dynamic-typing conditional-types

说我有以下两种类型:

export type CollectionNames = 'twitter:tweets' | 'twitter:users' | 'twitter:metadata-cashtag'

export type CollectionType<T extends CollectionNames> = 
    T extends 'twitter:tweets' ? Tweet :
    T extends 'twitter:users' ? User :
    T extends 'twitter:metadata-cashtag' ? CashtagMetadataDb :
    never

我觉得这很笨拙,而且我不太热衷于两次弦乐。同样,在后一种类型中可能会误将它们拼写错误。

有什么方法可以从这样的对象动态创建它们:

typings = {
    'twitter:tweets': Tweet,
    'twitter:users': User,
    'twitters:metadata-cashtag': CashtagMetadataDb
}

这个想法是,多个模块将具有自己的CollectionType类型,然后在导入的根模块中聚合为一个CollectionType。因此,如果我有两个使用Coin导入的模块Twitter* as,则看起来像这样:

type CollectionName = Twitter.CollectionNames | Coin.CollectionNames

type CollectionType<T extends CollectionName> = 
    T extends Twitter.CollectionNames ? Twitter.CollectionType<T> :
    T extends Coin.CollectionNames ? Coin.CollectionType<T> :
    never

然后将这些类型用于类似的函数中,其中类型是后一种类型(Collection来自MongoDB):

async function getCollection<T extends CollectionName> (name: T): Promise<Collection<CollectionType<T>>>

1 个答案:

答案 0 :(得分:2)

我认为在这种情况下,您根本不需要条件类型;您可以改为使用keyof and lookup types。您可能可以创建一个像typings的对象并从中派生类型,但是除非您在运行时需要该对象用于某种东西(并且拥有类型Tweet,{{ 1}}等)我想说的是,您应该只创建这样的接口类型:

User

然后,可以根据该类型定义您的export interface Collections { 'twitter:tweets': Tweet, 'twitter:users': User, 'twitter:metadata-cashtag': CashtagMetadataDb } CollectionNames类型:

CollectionType

您可以验证上述类型是否与您的定义相同。如果您有多个导出了export type CollectionNames = keyof Collections; export type CollectionType<K extends CollectionNames> = Collections[K]; 类型的模块,则可以简单地使用接口扩展合并它们,并从中导出CollectionsCollectionNames

CollectionType

希望有帮助。祝你好运!