问题
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