-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Passing an intersection of a generic type with a concrete type to generic superclass, which then uses it via indexed access + Parameters
utility to determine rest parameters produces surprising (potentially incorrect?) results
#50145
Comments
See #50066 and many others. |
Hey, thanks for the quick response. Reading through the issue and related issues, and trying to wrap my head around it. If I understand it correctly, does that mean that by the time that What's actually causing the issue here? Is it the You mention in the linked issue that “Constraints are not taken into consideration.”. Does that mean that the type EventRecord = Record<string, (...args: any[]) => void>;
class Bar<T extends EventRecord> {
x: T;
}
class Foo<T extends EventRecord> extends Bar<T & { a: () => void }> {
foo() {
this.x.a();
}
} Does this only happen when generic methods/functions are also involved? |
Within your In your
Yes, it limits what type can be provided for
It's not using a conditional type. |
Oh, that makes sense then. Thanks for helping me understand this! I had thought of conditional types as being limited to BTW, is the reason behind this not being supported performance? Could it get potentially out of hand due to recursion? Or would it lead to much greater complexity on the type checker? Would it be possible to somehow internally "flag" this type as "deferred" (or rely on an already existing internal flag) to display a more specific error message? Maybe something like:
Edit: For anyone finding this thread in the future with a similar problem, I was able to work around the limitation by using a type assertion with the parent type without the generic type: (this as MyEmitter<ChildEvents>).emit('hello');
(this as MyEmitter<ChildEvents>).emit('hello-with-message', 'Sup?'); |
You are actually correct on point 1 here - but the built-in utility types are actually defined externally (in library files like Incidentally the distributive case is generally why conditional types have to be deferred even when it looks like they can be resolved in advance: the input type might be a union of any size so eagerly taking only the true or false branch would be premature. (On this last note I’ve found with TS that when generics fail to typecheck in cases where it looks like they should, it’s almost always because you’ve failed to account for the possibility of instantiating them with union types. Having two things typed as |
You'd need a completely new kind of reasoning to make this work. Today, we can make good inferences when we see that something is true. But what you need here is a kind of inference that says something couldn't possibly be false -- that it's definitely impossible to construct a type that fits |
I'm not sure the inheritance is necessarily related to this issue. See this example: export type Handler = (...payload: any[]) => void;
export type EventDefinition = Record<string, Handler>;
type WSMessages = {
connect(socketId: number): void;
}
export class WS<CustomMessages extends EventDefinition> {
f() {
const b: Parameters<(CustomMessages & WSMessages)["connect"]> = [5];
}
} I wonder if it would be possible to know that the the Parameters of the function had to be [number], because of the way that & works: there is no way for any generic type as specified in |
could my issue be related to this? playground link |
I checked the latest beta (5.4.0) and this does not seem to be fixed there. Should this have been closed as "not planned" or is this actually fixed? |
The bulk "Close" action I applied to Design Limitation issues doesn't let you pick what kind of "Close" you're doing, so don't read too much into any issue's particular bit on that. I wish GitHub didn't make this distinction without a way to specify it in many UI actions! The correct state for Design Limitation issues is closed since we don't have any plausible way of fixing them, and "Open" issues are for representing "work left to be done". |
Hey there 👋 I believe this is a bug. I struggled to find anything related given that the error message is fairly common but this specific usage ends up combining a lot of features in a way that's a bit hard to describe/search. If it turns out this is either not a bug (and is instead a soundness issue with my approach) or if this is a duplicate, sorry in advance.
Bug Report
🔎 Search Terms
Spread, Rest, Generic, Indexed Access, Inheritance, Intersection
🕗 Version & Regression Information
⏯ Playground Link
Playground link with relevant code
💻 Code
🙁 Actual behavior
The code above fails producing the two following errors:
🙂 Expected behavior
Some background: I have a custom, strongly typed generic event emitter. I then create a generic subclass that inherits from it and specifies a few events that are supported, while also allowing future descenders to specify their own events, by using an intersection type with a generic parameter.
I expected to be able to use the concrete events I just specified with the
emit()
function inherited from the superclass without issue.The text was updated successfully, but these errors were encountered: