born2net
born2net

Reputation: 24953

Can't seem to create an interface to satisfy TypeScript getting missing property

I am trying to create an interface to make TypeScript happy. I am doing:

@Output() onChange:IMyEvent<ISliderItemData> = new Subject().delay(300).debounceTime(1000) ;// emits ISliderItemData

but I'm getting the following error:

Error:(68, 5) TS2322:Type 'Observable<{}>' is not assignable to type 'IMyEvent<ISliderItemData>'.
  Property '__isAsync' is missing in type 'Observable<{}>'.

I tried to satisfy TS with the following code but it did not work:

class IMyEvent<T> extends Subject<T> {
    __isAsync: boolean;
}

any ideas?

Upvotes: 0

Views: 872

Answers (3)

snorkpete
snorkpete

Reputation: 14564

As you indicated,

@Output() onChange:IMyEvent<ISliderItemData> = new Subject().delay(300).debounceTime(1000) ;// emits ISliderItemData

You are taking a Subject and then calling the delay operator on it. At that point, you no longer have a Subject - you instead have an Observable. Any further operators chained onto that will also return Observables. Therefore, the result of your expression (i.e. the stuff on the right of the '=') is an Observable. Hence, Typescript expects your declaration on the right to be of a matching type i.e. an Observable.

So, the simplest form of this would be:

@Output() onChange: Observable = new Subject().delay(300).debounceTime(1000) ;// emits ISliderItemData

However, in your case, you want to type your onChange variable to indicate what type the Observable emits. You should also type your Subject so that it matches. So, this becomes:

@Output() onChange: Observable<ISliderItemData> = new Subject<ISliderItemData>().delay(300).debounceTime(1000) ;// emits ISliderItemData

The reality is that Typescript is pretty smart about inferring types based on usage, so you could actually use:

@Output() onChange = new Subject<ISliderItemData>().delay(300).debounceTime(1000) ;// emits ISliderItemData

The Typescript compiler will see that the return type of your delay operator (and resulting debounceTime operator) is Observable and automatically assign that type to your onChange instance variable.

It's personal preference in this case whether you bother to put the type on the onChange variable - it's not needed by the compiler but can be useful to add some code clarity.

Upvotes: 0

Jan Cejka
Jan Cejka

Reputation: 331

I did not test it but I would guess following might work:

@Output() onChange:IMyEvent<ISliderItemData> = <IMyEvent<ISliderItemData>>(new Subject().delay(300).debounceTime(1000)) ;

Why you don't define folloowing?

class IMyEvent<T> extends Observable<T> {
    __isAsync: boolean;
}

and then using: @Output() onChange:IMyEvent<ISliderItemData> = new IMyEvent<ISliderItemData>().delay(300).debounceTime(1000) ;

That would create typed Subject (and be converted to Observable by delay() and debounceTime())

Edit: I have changed original answer - Subject to IMyEvent. On top - if I see the code and comments - I believe it would be better to keep clean Subject to be able to call next() as you need and use delay() and debounceTime() on consuming side.

Upvotes: 1

born2net
born2net

Reputation: 24953

So as @jonrsharpe said, you can do it on the push side, but if you want to do it at declaration, this will work:

@Output() onChange:Observable<ISliderItemData> = new Subject().delay(300).debounceTime(1000);

...

and later:

 (this.onChange as Subject<ISliderItemData>).next({data})

Upvotes: 0

Related Questions