There is some event type: For example,
interface Event {
type: 'a' | 'b' | 'c';
value: string;
}
interface App {
elements: Event[];
}
It's not bad, but I could do the following thing:
const app: App = {
elements: [
{ type: 'a', value: '1' },
{ type: 'a', value: '2' },
],
}
But I need that elements array contains objects with uniq type (only one item with type 'a', only one item with type 'b', etc). How could I do it in TypeScript? Thanks in advance!
CodePudding user response:
You might be able to adapt this answer to your situation (your union would be of distinct SomeEvent
types, which you can generate from your existing type). It's complicated and I couldn't do it in the time I gave it, but it may be possible.
It would simpler, though, to use an object instead of an array, keyed by the type: elements: {a: { value: "1" } }
. (If you need to get an array from it at some point, you can always use Object.values(theApp.elements)
to get it, but you can easily loop through objects, not just arrays.)
interface SomeEvent {
type: 'a' | 'b' | 'c';
value: string;
}
interface App {
elements: Partial<{
[key in SomeEvent["type"]]: Omit<SomeEvent, "type"> & { type: key};
}>
}
That uses the type as an object key, and requires the object assigned to it to have the same value as typd
. (I used the name SomeEvent
instead of Event
to avoid confusing with DOM events.)
Then this works:
const app1: App = {
elements: {
a: { type: 'a', value: '1' },
b: { type: 'b', value: '2' },
},
};
but this has an error as desired:
const app2: App = {
elements: {
a: { type: 'a', value: '1' },
a: { type: 'a', value: '2' }, // An object literal cannot have multiple properties with the same name in strict mode.
},
};
CodePudding user response:
one way can be to create an interface for Event with different type a, b or c
you can create an interface that will say your elements property can have one instance of each type
interface EventFilter {
elements: [EventA?, EventB?, EventC?];
}
The limitation of this solution is that element should be added in the order defined in EventFilter
interface Event {
type: 'a' | 'b' | 'c';
value: string;
}
interface EventA extends Event {
type: 'a';
}
interface EventB extends Event {
type: 'b';
}
interface EventC extends Event {
type: 'c';
}
interface EventFilter {
elements: [EventA?, EventB?, EventC?];
}
const app: EventFilter = {
elements: [
{ type: 'a', value: '1' },
{ type: 'b', value: '1' }
],
}
unfortunately, you will have to list all authorised combine to be able to have a flexible array with element in any order
interface EventFilter {
elements: [EventA?, EventB?, EventC?] | [EventA?, EventC?, EventB?]
| [EventB?, EventA?, EventC?] | [EventB?, EventC?, EventA?]
| [EventC?, EventA?, EventB?] | [EventC?, EventB?, EventA?];
}
const app: EventFilter = {
elements: [
{ type: 'c', value: '1' },
{ type: 'a', value: '1' },
],
}