Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
alexandercerutti opened this issue Nov 2, 2018 · 3 comments
Closed
Labels
Question An issue which isn't directly actionable in code

Comments

@alexandercerutti
Copy link

alexandercerutti commented Nov 2, 2018

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.

@weswigham weswigham added the Question An issue which isn't directly actionable in code label Nov 2, 2018
@weswigham
Copy link
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.

@alexandercerutti
Copy link
Author

@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.

@weswigham
Copy link
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

2 participants