TypeScript interface contravariance

As an intelligent exercise, I thought that I would see how I could implement some of the .Net generators in TypeScript (0.9.5), I got to List<T>, but not sure, I can progress.

(I understand that there are workarounds for this, but I'm specifically trying to use the same implementation as in .Net libs, mainly to try to understand the limitations still present in TypeScript).

In any case, ignoring the fact that I seem to be unable to overload my constructors in any meaningful way, in the .Net source the constructor List(IEnumerable<T> collection)checks that the passed Enumerable is not null and then drops it contravariantly to ICollection using ICollection<T> c = collection as ICollection<T>.

In TypeScript, I do this var c: ICollection<T> = collection(the collection is IEnumerable<T>), but gets the following error:

Cannot convert 'IEnumerable<T>' to 'ICollection<T>': Type 'IEnumerable<T>' is missing property 'Add' from type 'ICollection<T>'.

My current code is as follows:

export module System {

    export module Collections {

        export interface IEnumerator {
            MoveNext(): boolean;
            Reset(): void;
            Current(): any;
        }
        export interface IEnumerable {
            GetEnumerator(): IEnumerator;
        }
        export interface ICollection extends IEnumerable {
            CopyTo(array: any[], index: number): void;
            Count(): number;
            SyncRoot(): any;
            IsSynchronized(): boolean;
        }
        export interface IList extends ICollection {
            [index: number]: any;
            Add(value: any): number;
            Contains(value: any): boolean;
            Clear(): void;
            IsReadOnly: boolean;
            IsFixedSize: boolean;
            IndexOf(value: any): number;
            Insert(index: number, value: any): void;
            Remove(value: any): void;
            RemoveAt(index: number): void;
        }

        export module Generic {

            export interface IEnumerator<T> extends System.Collections.IEnumerator {
                Current(): T;
            }
            export interface IEnumerable<T> extends System.Collections.IEnumerable {
                GetEnumerator(): IEnumerator<T>;
            }
            export interface ICollection<T> extends IEnumerable<T> {
                Add(item: T): void;
                Clear(): void;
                Contains(item: T): boolean;
                CopyTo(array: T[], arrayIndex: number): void;
                Remove(item: T): boolean;
                Count(): number;
                IsReadOnly(); boolean;
            }
            export interface IList<T> extends ICollection<T> {
                IndexOf(item: T): number;
                Insert(index: number, item: T): void;
                RemoveAt(index: number): void;
                [index: number]: T;
            }
            export interface IReadOnlyCollection<T> extends IEnumerable<T> {
                Count(): number;
            }
            export interface IReadOnlyList<T> extends IReadOnlyCollection<T> {
                [index: number]: T;
            }

            export class List<T> implements IList<T>, System.Collections.IList, IReadOnlyList<T> {
                private _defaultCapacity: number = 4;

                private _items: T[];
                private _size: number;
                private _version: number;
                private _syncRoot: any;

                constructor(collection?: IEnumerable<T>, capacity?: number) {
                    // NOTE: Capacity will be ignored is Collection is not null
                    //       This is because we don't appear to be able to overload ctors in TypeScript yet!
                    if (collection == null) {
                        if (capacity == null) {
                            this._items = new Array<T>(0);
                        }
                        else {
                            this._items = new Array<T>(capacity);
                        }
                    } else {
                        var c: ICollection<T> = collection;

                    }
                }
            }
        }
    }
}

Has anyone else tried to match / contradict interfaces? If so, how are you?

Thanks,

+4
source share
2 answers

While TypeScript does not support direct co / contra-variance support, you can simply use the type statement in this instance (which is similar to casting in other languages ​​such as C #):

var c: ICollection<T> = <ICollection<T>>collection;

TypeScript does not have a simple confirmation that the type assertion operation is correct (for example, the object collectionis actually ICollection<T>), so you need to decide if this is important to you.

, , capacity:

constructor(collection?: IEnumerable<T>, capacity: Number = 0) {
    if (!collection) {
       this._items = new Array<T>(capacity);
    } else {
       var c: ICollection<T> = <ICollection<T>> collection;
    }
}

TypeScript , :

if (typeof capacity === "undefined") { capacity = 0; }
+2

, TypeScript:

var c: ICollection<T> = <ICollection<T>> collection;

- , . .

, add.

, null :

if (collection == null) {

null , , , undefined, . , :

if (!collection) {

, , , - , , List and Collection method-for-method, .NET TypeScript ( JavaScript) - . TypeScript , - . , , .

+5

Source: https://habr.com/ru/post/1523907/


All Articles