The problem with your type is that it is inconsistent with regard to the string index signature ([key: string] : IItem;). Not all keys accessed this way will be of type IItem if you inherit array. For example myArray['map'] will be the array function not IItem. This is the reason typescript forces the string index signature to be compatible with ALL statically declared members of the interface.
There is a loophole in this check though. The intersection type loophole. We can declare ICustomArray as an intersection of array and a type that has the index signature.
export type ICustomArray = Array<IItem> & {
[key: string] : IItem;
}
let item: IItem;
const myArray: ICustomArray = [] as ICustomArray
myArray.push(item)
myArray[item.key] = item;
This will mostly have work the way you would expect:
let o = myArray['map'] // o is a function of type <U>(callbackfn: (value: IItem, index: number, array: IItem[]) => U, thisArg?: any) => U[]
let i = myArray['key'] //IItem
declare let randomStr: string
let d = myArray[randomStr] //IItem .. but if randomStr= map, we have a runtime problem