Skip to content

TS reporting a non-existing error with Generic Interfaces extension #28315

Closed

Description

Hello everybody! I was trying to build a queue system class to be extended with other classes.
The first design was about using a common array for multiple elements of different queues mixed together. The second design, instead, was about to use the following queue structure:

{
    "<identifier>": [ { Function }, { Function }, ... ]
}

or

{
    "<indentifier>": [ { string } ]
}

This because I'm going to use two classes (ReplyManager and OperationManager) to extend the queue. These two classes have a different parameter of the array. Therefore I thought to to the model to describe these structures. I came out with this reasoning:

interface QueueObject<T> {
	// @ts-ignore - Hashable is a string or number yet. ( This might be another bug )
	[key: Hashable]: T[]
}

The QueueObject is the base object that will bind the two classes which will extend Queue.

interface OperationDescriptior {
	command: string
}

interface ReplyDescriptor {
	action: Function,
	previousData?: any
}

These are the descriptors of the content of the arrays, one per class.

export type Reply = QueueObject<ReplyDescriptor>;
export type Operation = QueueObject<OperationDescriptior>;
export type QueueExtendableObject = Reply | Operation;

export type Hashable = number | string;

In the end we have Reply and Operation which are the Real objects I'm going to use, and QueueExtendableObject, which is the one I'm going to use in the Queue class that has the following signature:

class QueueManager<T extends QueueExtendableObject> {
    private _queue : T = <T>{}
};

I try to populate the queue object and everything goes fine, but in ReplyManager I have the following method:

execute(id: Hashable, data: ReplyData = {}) {
	let next: Reply = this.get(id);
	let callback: Function = next.action;

	data.previousData = next.previousData || undefined;

	let result = callback(data);
	// ...
}

and since I have access to the QueueManager, I can use this.get(id), which has the following characteristics:

Code:

protected get(id: Hashable): T {
	return this._queue[id] && this._queue[id].length ? this._queue[id][0] : { action: () => { } };
}

Return type: QueueObject<ReplyDescriptor>.

I mean, it makes sense, that's what I wanted!

But there is a problem: in execute, action and previousData of next are underlined in red and give this error:

Property (action | previousData) does not exist on type QueueObject<ReplyDescriptor>.

I tried to execute a sample code I wrote to put these class at work and if I log next after this.get, it will return, as expected, an object with both "action" and "previousData" (if exists).

That's why I think this may be a bug.
Since, as you can see, I've already used ts-ignore once in the code above, this time I just don't want to ignore but understand.

This is the form.

TypeScript Version: 3.1.3

Search Terms:

"property does not exist in interface", "non existing error"

Expected behavior: No alert.

Actual behavior:

The same error applied on two properties:
Property (action | previousData) does not exist on type QueueObject<ReplyDescriptor>

image

Thank you.

Activity

  1. weswigham commented on Nov 2, 2018

    @weswigham
    Member

    Since, as you can see, I've already used ts-ignore once in the code above, this time I just don't want to ignore but understand.

    Remove your @ts-ignore and fix the underlying error - it's what's causing the given fields to not be present. You should just have [index: string]: T[]. Reply is a QueueObject, which just has an index signature; except since that index signature contains an error it effectively doesn't exist - so QueueObjects are all just propertyless types.

    For future reference: questions like this are usually better suited to stack overflow - way more people look over that than here.

  2. alexandercerutti commented on Nov 2, 2018

    @alexandercerutti
    Author

    Wesley Wigham (@weswigham) thanks for the reply.
    Why [index: string] ? My interface is not an array but an object. I should use [key: string], instead, shouldn't I? I wanted to use both numbers or strings (a.k.a. Hashable), but maybe it has no sense to use both. Anyway, applying the suggestion you gave me, the error changed a lot and everything is like fucked up 😂.

    I found some design errors like the type of the queue (which should be QueueObject<T> and not T itself) and the T in generic class, which had not to be a QueueObject but the type to pass to a QueueObject.

    Yeah, about Stack overflow, I was in doubt if put here or there. Since I was thinking it was a bug, I preferred post it there. Instead, well, it was a misusage of ts-ignore 😊

    Thank you very much again.

  3. weswigham commented on Nov 3, 2018

    @weswigham
    Member

    I wanted to use both numbers or strings (a.k.a. Hashable), but maybe it has no sense to use both

    Just provide two index signatures then - one for number, and one for string.

  4. locked as resolved and limited conversation to collaborators on Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    QuestionAn issue which isn't directly actionable in code

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions