1
interface Parent {
    id: number;
}

interface ChildA extends Parent {
    desc: string;
}

interface ChildB extends Parent {
    eatable: boolean;
}

let arr: Array<Parent> = []

arr.push({
    id: 1,
    desc: "test"
});

arr.push({
    id: 2,
    eatable: false
});

I have two different types with shared properties in my webapp, and i'd like to be able to have instances of these be stored in an array, to loop through when i only need to display the shared properties. How can i do this? The above code gives a type error.

Update #1:

How come i am not able to do the above, but i am able to do the following? This gives me, type-wise, exactly the same as the top example.

let arr: Parent[] = []
let tmp_arr: (ChildA | ChildB)[] = [];
arr = tmp_arr;

tmp_arr.push({
    id: 1,
    desc: "test"
});

tmp_arr.push({
    id: 2,
    eatable: false
});

for (let child of arr) {
    console.log(child.id);
} 
//(console: 1, 2)

1 Answer 1

3

You are stating that your array has only members with id property but they have more fields. In order to achieve what you need we can use union operator |

 Array<ChildA | ChildB>

Also I propose to model types differently, consider:

interface Base {
    id: number;
}

interface ChildA extends Base {
    desc: string;
}

interface ChildB extends Base {
    eatable: boolean;
}

type Final = ChildA | ChildB;

// and now
let arr: Array<Final> = []

Additional info because of the question in the comment

{
    let arr: Parent[] = [{ id: 1 }]
    let tmp_arr: (ChildA | ChildB)[] = [];
    tmp_arr = arr; // error as Parent is not assinable to ChildA | ChildB
}
{
    let arr: Parent[] = []
    let tmp_arr: (ChildA | ChildB)[] = [];
    arr = tmp_arr; // no error as ChildA | ChildB has all fields required by Parent
}

You can assign type which is more restricted(is a subset) to the more loose type, but you cannot in other way round because if you do your type does not pass the requirements. For example you cannot use Parent[] as (ChildA | ChildB)[] as Parent has less fields

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks! I didn't think of the union operator. This does however raise another question, as posed in my update :)
TS is structural typed language, doing arr = tmp_arr; you are not changing the type, [] is valid member for both types so it can be passed.
Added you more info in the answer
Right, so i was originally hoping i could push ChildA and ChildB directly to a Parent[] array, since they have all required fields. It's still not clear to me why having all required fields is good enough for assigning arrays, but not for pushing to them. But i guess, in the end, that's just a design choice.
such behavior works only with literal types, so if you put this to the variable it will work as I said. Literals types are strict in both ways

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.