Create typings dynamically from object

廉价感情. 提交于 2020-01-16 08:36:29

问题


Say I have the following two 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

I feel this is very clunky and I'm not very keen on having the strings twice. Also it's possible to legally misspell them in the latter type.

Is there any way to create these dynamically from an object such as this:

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

The idea is that multiple modules will have their own CollectionType type which is then aggregated into one CollectionType in the importing root module. So if I have two modules Coin and Twitter imported using * as, it looks something like this:

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

These will then be used in a function like so where the types are of the latter kind (Collection here is from MongoDB):

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

回答1:


I think in this case you don't need conditional types at all; you can do this with keyof and lookup types instead. You probably could create an object like typings and derive a type from it, but unless you need that object for something at runtime (and have objects of type Tweet, User, etc lying around) I'd say you should just make an interface type like this:

export interface Collections {
  'twitter:tweets': Tweet,
  'twitter:users': User,
  'twitter:metadata-cashtag': CashtagMetadataDb
}

Then, your CollectionNames and CollectionType types can be defined in terms of that type:

export type CollectionNames = keyof Collections;
export type CollectionType<K extends CollectionNames> = Collections[K];

You can verify that the above types act the same as your definitions. In the case that you have multiple modules that have exported Collections types, you can simply merge them using interface extension and re-derive CollectionNames and CollectionType from it:

export interface Collections extends Twitter.Collections, Coin.Collections {}
export type CollectionNames = keyof Collections;
export type CollectionType<K extends CollectionNames> = Collections[K];

Hope that helps. Good luck!



来源:https://stackoverflow.com/questions/52092690/create-typings-dynamically-from-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!