-
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
this
type is not assignable to NonNullable<this>
#22934
Comments
That's because a generic is a class definition not an instance. this is an instance. Your code should look like: class X {
fn(): void {
const x: NonNullable<X> = this;
}
} |
@sandersn seems like a bug but I might be missing something extra-subtle |
Why should dynamic objects be allowed as generic definitions? |
I may have whittled down the actual issue I was dealing with too much. Here is an example of the bug I was trying to be succinct with: export class Entry<T extends Table> {
private _table: T | null = null;
createSubsetForDirectory(): void {
const entry = new Entry<T>();
// error TS2345: Argument of type 'Entry<T>' is not assignable to parameter of type 'Entry<NonNullable<T>>'.
// Type 'T' is not assignable to type 'NonNullable<T>'.
// Type 'Table' is not assignable to type 'NonNullable<T>'.
this._table!.fn(entry);
// ~~~~~
}
}
export abstract class Table {
fn(directoryEntry: Entry<this>): this | null {
return null;
}
}
Playground Link: |
@aschmois In this case, I'm using |
@athasach that's actually a much more serious repro as it's a regression from 2.7. That code worked as far back as 2.0 |
Pinging @weswigham. I suspect this is related to #22096. |
I will say that the current behavior doesn't seem totally wrong. In general, a type parameter |
This is just what falls out from conditional type assignability rules, I suppose. The example in the OP didn't use the class X {
fn(): void {
// Type 'this' is not assignable to type 'NonNullable<this>'.
// Type 'X' is not assignable to type 'NonNullable<this>'.
const x: NonNullable<this> = this;
// ~
}
} It seems like the issue is mostly that |
Yes, I did make a change where distributive conditional types are always deferred if the checked type is generic, but I think it stayed generic before as well. It may be that that |
I'm pretty sure it'd be correct to (re)build that logic into conditional types in general at that point, since nothing about that logic would be specific to either null or undefined. One of the motivating examples for conditional types is non-null types; it'd be off that And again, the original issue doesn't involve |
@weswigham In principle I agree, but devising the exact logic by which this would happen isn't trivial. We currently defer resolution for distributive conditional types when the check type is generic. Even in cases where we know that the check will always go a certain way (e.g. because of a constraint), we still need to defer because the generic type may be instantiated to a union type that we want to distribute over. Only when we can conclude that distributing over a union wouldn't affect the outcome can we actually consider resolving early. I think it would pretty much amount to recognizing Exclude- and Extract-like types. It may be worth doing, but building it into the |
This one was fixed by the infamous #49119, as that changed the definition of |
TypeScript Version: 2.8.1
Search Terms: NonNullable, this
Code
Expected behavior:
A reference of type
this
should be assignable to aNonNullable<this>
within a method.Actual behavior:
this
is not assignable toNonNullable<this>
.Playground Link:
http://www.typescriptlang.org/play/#src=class%20X%20%7B%0D%0A%20%20%20%20fn()%3A%20void%20%7B%0D%0A%20%20%20%20%20%20%20%20const%20x%3A%20NonNullable%3Cthis%3E%20%3D%20this%3B%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A
Related Issues:
The text was updated successfully, but these errors were encountered: