-
Notifications
You must be signed in to change notification settings - Fork 433
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
[Bug]: Queue<DataTypeOrJob>
wrong variance
#2951
Comments
As I am not an expert on typescript generics and less so on variance and contra variance I asked ChatGPT o1: Variance Types:
TypeScript’s Default Behavior:
Enforcing Correct Variance in Queue To prevent unsafe assignments, we need to make DataTypeOrJob invariant or contravariant in the Queue class. Why Contravariant?
However, TypeScript does not currently support variance annotations (in or out keywords) on type parameters. Instead, variance is inferred based on how the type parameters are used within the class. Solution: Adjusting the Queue Class to Enforce Invariance To make DataTypeOrJob invariant, we need to ensure it’s used in both input and output positions within the Queue class. This forces TypeScript to treat the type parameter as invariant. Step 1: Use DataTypeOrJob in Output Positions Add a method to the Queue class that returns a value of type DataTypeOrJob. Example: export class Queue<DataTypeOrJob = any> {
// Existing methods
// Add a method that returns DataTypeOrJob
getData(): DataTypeOrJob {
// Implementation not important for type checking
throw new Error('Not implemented');
}
} Step 2: Ensure DataTypeOrJob is Used in Input Positions add(data: DataTypeOrJob): void {
// Implementation
} Result: By using DataTypeOrJob in both input and output positions, TypeScript treats it as invariant. This means that Queue is no longer assignable to Queue<string | number>, and the unsafe assignment in your example will produce a compile-time error. Testing the Adjusted Queue Class export class Queue<DataTypeOrJob = any> {
add(data: DataTypeOrJob): void {
// Implementation
}
getData(): DataTypeOrJob {
// Implementation
throw new Error('Not implemented');
}
}
// Your example
async function sendNumberToQueue(queue: Queue<string | number>) {
await queue.add(1);
}
declare const stringQueue: Queue<string>;
void sendNumberToQueue(stringQueue); Compiler Error:
Explanation
Alternate Approach: Using TypeScript’s strictFunctionTypes Ensure that your tsconfig.json has the following setting:
|
It's strange o1 doesn't know about variance annotations even though they were clearly added more than a year before its knowledge cutoff (in TS 4.7, 2022). I have also not seen it be that wrong before, the proposed still doesn't work Note the I would be open to put out a small MR for adding variance annotations, but that would prevent anyone from using TS <4.7 from upgrading to the latest version of this package. But perhaps that's a good thing. |
Version
v5.31.0
Platform
NodeJS
What happened?
I have only a very shallow understanding of variance yet, please do correct me if I use terminology incorrectly. I believe the issue holds regardless of what you name the factors involved, though.
The
Queue
class should be contravariant onDataOrJobType
, as it's an input type. The generated types however allow it to be used contravariantly, leading to unsafe code.Should be as simple as adding an
in
keyword to the type parameter here. If you modify your local .d.ts file accordingly, the below reproduction correctly errors. I'm not fully sure whether to give it thein
tag only or whether it's invariant within out
.How to reproduce.
Should error for
stringQueue
is only aware about string messages.Relevant log output
No response
Code of Conduct
The text was updated successfully, but these errors were encountered: