[TypeScript] How would you go about creating an Array that can have different types of objects?

Firstly sorry if this isn't the right place to ask TS question, but I didn't know where else to ask 😢 I have a dilemma in a project I am working on. The example I will give is not how we do it, but you should get the idea... The project is about task solving and because of some cases we have decided to have a type like so:
type User = {
id: string,
name: string,
tasks: Array<TaskType1 | TaskType2 | TaskType3>
}
type User = {
id: string,
name: string,
tasks: Array<TaskType1 | TaskType2 | TaskType3>
}
Where the tasks array holds all the user's tasks. But like you can see anyone of these elements in the array can be of a completely different type. What I want to do is render a different component based on what type of object it is, so I do this:
const user: User = {...}

user.tasks.map((x) => {
return <Component />
})
const user: User = {...}

user.tasks.map((x) => {
return <Component />
})
However, since it doesn't know what type it is, I don't get type safety. How can I check which type it is? Is that even possible? Also, keep in mind that in the future we might add more task types so I have to take that into account as well.
15 Replies
JulieCezar
JulieCezar•3y ago
[EDIT] I have tried using typeof, however i cannot compare object types only primitives. Except if I do something like this, but it seems to complicated for this use case:
const user: User = {...}

user.tasks.map((x) => {
function isType<T>(obj: any): obj is T {
return obj;
}

if (isType<Type1>(x))
return <Component />

... need to check for all other types
})
const user: User = {...}

user.tasks.map((x) => {
function isType<T>(obj: any): obj is T {
return obj;
}

if (isType<Type1>(x))
return <Component />

... need to check for all other types
})
or this, which seems even more weird:
user.tasks.map((x) => {
const tempType: Type1 = {
... fill all properties just to have a proper object
}

if (typeof x === typeof tempType)
return <Component />

... still need to check for all other types
})
user.tasks.map((x) => {
const tempType: Type1 = {
... fill all properties just to have a proper object
}

if (typeof x === typeof tempType)
return <Component />

... still need to check for all other types
})
Unknown User
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
JulieCezar
JulieCezar•3y ago
Nice, Thank you! But does this only work if I have a unique property in a type?
Unknown User
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
JulieCezar
JulieCezar•3y ago
Some of them match, for example we have: name, maxPoints, points... However some are called the same but have different types, for example: results. Some are just string, some are Array<string>, or Array<SomeStructure>
cje
cje•3y ago
just give them a shared key like tasktype: 'something' | 'somethingElse' then you can do a discriminated union on them
Unknown User
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
JulieCezar
JulieCezar•3y ago
I see now, if they all have the same prop TS is smart enough to give type safety for just that one...
JulieCezar
JulieCezar•3y ago
Tyvm both of you, you solved it for me 💪
cje
cje•3y ago
read through this docs page theres a lot of good stuff in it
JulieCezar
JulieCezar•3y ago
Doesn't matter that it's deprecated?
cje
cje•3y ago
oh my bad theres a link to the new version in the thing that says that its deprecated i think this page didnt change though
Unknown User
Unknown User•3y ago
Message Not Public
Sign In & Join Server To View
scatter
scatter•3y ago
the reason, btw, that you have to add (or use an existing) a discriminating property is that typescript is compile time ONLY so just because typescript knows at compile time that it added some numbers, strings, Circles, Squares, whatever, to an array there’s no way for it to know what’s what when looping unless there’s something concretely different about the elements, something you can test for with JS
Want results from more Discord servers?
Add your server