César Alberca
César Alberca

Reputation: 2681

Typescript intersection types with array of objects and an interface

I'm having a lot of trouble understanding the intersection types. Here it is what I'm referring to:

type FooList = Foo[] & {
    bar: string
};

interface Foo {
    baz: string;
}

After a lot of fiddling I'm unable to create a typed array of FooList.

These typings are not mine, they are from this library.

Does these types mean FooList must be an array of Foos and also have an object bar? Does each Foo object has to contain a property bar?

Here is the link to the playground

Upvotes: 5

Views: 6268

Answers (3)

jcalz
jcalz

Reputation: 328758

A FooList is both an array of Foo objects, as well as an object that contains a string-valued bar property.

If you're willing to use type assertions, it's easy enough to create one since you can just tell the compiler you know what you're doing:

var foos: any; // turn off type checking
foos = [{ baz: 'baz1' }, { baz: 'baz2' }];
foos.bar = 'bar';
var fooList: FooList = foos as FooList; // assert type of fooList

Creating one of these things safely, where the compiler guarantees that you've made something of the right type is a little tricky, but you can do it with Object.assign(), which returns an intersection of its parameter types:

const fooList: FooList = Object.assign([{ baz: 'baz' }, { baz: 'baz' }], { bar: 'bar' });

Hope that helps. Good luck!


Please ignore the stuff below; I'm not sure what came over me, but spreading an array into an object is unlikely to work the way anyone wants, since Array prototype methods will not be copied. Just use the above Object.assign() solution.

Update 1

@CésarAlberca said:

Thanks! Yours was my preferred solution. What is the equivalent of object assign using the spread operator?

Oh, sure, you could do that:

const fooList2: FooList = { ...[{ baz: 'baz' }, { baz: 'baz' }], ...{ bar: 'bar' } };

or

const fooList3: FooList = { ...[{ baz: 'baz' }, { baz: 'baz' }], bar: 'bar' };

Cheers.

Upvotes: 4

J. Konárek
J. Konárek

Reputation: 9

Look at my demo of usage.

type LinkedList<T> = T & { next: LinkedList<T> };

interface Person {
    name: string;
}

var people: LinkedList<Person>;
var person: Person = { name: "Joey" };
var childPerson: Person = { name: "James" };
var grandChildPerson: Person = { name: "John" };

people = person;
people.next = childPerson;
people.next.next = grandChildPerson;

alert(JSON.stringify(people));

See typescript documentation of type aliases and intersection types

Upvotes: 0

Nitzan Tomer
Nitzan Tomer

Reputation: 164217

FooList is an array with items of type Foo which also has a string property named bar.

Here's how you'd create it:

function createFooList(bar: string, ...items: Foo[]): FooList {
    const arr = [] as FooList;
    arr.bar = bar;
    arr.push(...items);
    return arr;
}

Or:

function createFooList(bar: string, ...items: Foo[]): FooList {
    (items as FooList).bar = bar;
    return items as FooList;
}

Upvotes: 1

Related Questions