vdegenne
vdegenne

Reputation: 13270

How to declare a polymorphic data interface in Typescript?

I want to make an interface that represents my application data, basically my initial data object is :

const data = {
  wallet: { ... },
  orders: [{ ... }, { ... }, ...],
}

wallet and orders are initial properties.
Now the data object can have volatile properties that represents cryptocurrency objects.
For instance the data object can be of this form :

const data = {
  wallet: { ... },
  orders: [{ ... }, { ... }, ...],
  btc: { ... },
  eth: { ... },
  ...
}

Here's my typescript definition :

export interface Data {
  wallet?: any
  orders?: Order[]
  [cryptoname:string]: CryptoObject
}

but typescript returns this exception :

Property 'orders' of type 'Order[] | undefined' is not assignable to string index type 'CryptoObject'.ts(2411)

What am I doing wrong ?


EDIT: I understand why I get this exception now. Typescript expects all the properties to be a CryptoObject. My question is still opened because I wonder how to write the definition for this type of data structure.

Upvotes: 0

Views: 198

Answers (3)

vdegenne
vdegenne

Reputation: 13270

Thanks to @Kyll answer. What I needed was intersection type

export type Data = {
  wallet?: any,
  orders?: Order[]
} & {[cryptoname:string]:CryptoObject}

Upvotes: 1

Kyll
Kyll

Reputation: 7139

I would use an intersection type:

type Cryptos = 'btc' | 'eth'

type Data = {
    wallet?: any
} & Record<Cryptos, any>

const myData: Data = {
    wallet: 'foobar',
    btc: 123,
    eth: 456
}

See playground. You can fiddle around with the exact definition of your intersection to get the best results. If you want to make your Cryptos optional, use Partial<Record<Cryptos>>.

also don't use any please

Upvotes: 1

user12251171
user12251171

Reputation:

[cryptoname: string] is an index signature, which makes it so that:

As soon as you have a string index signature, all explicit members must also conform to that index signature.

So by using an index signature here, you're saying that all members of your Data interface need to be CryptoObjects. Which is obviously incompatible with Order[] | undefined.

I don't really have an answer how to solve it for you except for adding individual members for each crypto you want to support. Like:

export interface Data {
  wallet?: any
  orders?: Order[]
  btc?: CryptoObject
  eth?: CryptoObject
}

Upvotes: 2

Related Questions