Skip to content

Bug: Conditional types don't properly propagate this #28164

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
SLaks opened this issue Oct 26, 2018 · 1 comment
Closed

Bug: Conditional types don't properly propagate this #28164

SLaks opened this issue Oct 26, 2018 · 1 comment
Assignees
Labels
Domain: Conditional Types The issue relates to conditional types Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@SLaks
Copy link

SLaks commented Oct 26, 2018

TypeScript Version: 3.1.1-insiders.20180926

Search Terms: this conditional

Code

class Builder<T1, T2, T3, TWith>{
    private _noStructuralTyping: undefined;

    withBroken<TAlsoWith>() {
        return this as AddWith<this, TAlsoWith>;
    }
    withBroken2<TAlsoWith>(): AddWith<this, TAlsoWith> {
        return this;
    }
    withWorking<TAlsoWith>(): Builder<T1, T2, T3, TWith|TAlsoWith> {
        return this;
    }
}


type AddWith<TBuilder, TAlsoWith> = TBuilder extends
    Builder<infer T1, infer T2, infer T3, infer TWith>?
    Builder<T1, T2, T3, TWith|TAlsoWith>:
    never;

const test = new Builder<1, 2, 3, string>().withBroken<number>();

// Without using the `this` type, it works as expected:
const simpleTest = new Builder<1, 2, 3, string>();
type WithNumber = AddWith<typeof simpleTest, number>;
const demo: WithNumber = simpleTest;

Expected behavior:

this should be convertible to AddWith<this, whatever>

Actual behavior:

Type 'this' is not assignable to type 'AddWith<this, TAlsoWith>'.
  Type 'Builder<T1, T2, T3, TWith>' is not assignable to type 'AddWith<this, TAlsoWith>'.

Motivation:
I'm building a builder class which builds configuration both in the type system and at runtime.

I don't want to repeat all of the existing type parameters (which have long names) in every method that adds a type to TWith

Playground Link: http://www.typescriptlang.org/play/#src=class%20Builder%3CT1%2C%20T2%2C%20T3%2C%20TWith%3E%7B%0D%0A%20%20%20%20private%20_noStructuralTyping%3A%20undefined%3B%0D%0A%0D%0A%20%20%20%20withBroken%3CTAlsoWith%3E()%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20this%20as%20AddWith%3Cthis%2C%20TAlsoWith%3E%3B%0D%0A%20%20%20%20%7D%0D%0A%20%20%20%20withBroken2%3CTAlsoWith%3E()%3A%20AddWith%3Cthis%2C%20TAlsoWith%3E%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20this%3B%0D%0A%20%20%20%20%7D%0D%0A%20%20%20%20withWorking%3CTAlsoWith%3E()%3A%20Builder%3CT1%2C%20T2%2C%20T3%2C%20TWith%7CTAlsoWith%3E%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20this%3B%0D%0A%20%20%20%20%7D%0D%0A%7D%0D%0A%0D%0A%0D%0Atype%20AddWith%3CTBuilder%2C%20TAlsoWith%3E%20%3D%20TBuilder%20extends%0D%0A%20%20%20%20Builder%3Cinfer%20T1%2C%20infer%20T2%2C%20infer%20T3%2C%20infer%20TWith%3E%3F%0D%0A%20%20%20%20Builder%3CT1%2C%20T2%2C%20T3%2C%20TWith%7CTAlsoWith%3E%3A%0D%0A%20%20%20%20never%3B%0D%0A%0D%0Aconst%20test%20%3D%20new%20Builder%3C1%2C%202%2C%203%2C%20string%3E().withBroken%3Cnumber%3E()%3B%0D%0A%0D%0A%2F%2F%20Without%20using%20the%20%60this%60%20type%2C%20it%20works%20as%20expected%3A%0D%0Aconst%20simpleTest%20%3D%20new%20Builder%3C1%2C%202%2C%203%2C%20string%3E()%3B%0D%0Atype%20WithNumber%20%3D%20AddWith%3Ctypeof%20simpleTest%2C%20number%3E%3B%0D%0Aconst%20demo%3A%20WithNumber%20%3D%20simpleTest%3B
Related Issues: #28159

@weswigham weswigham added Bug A bug in TypeScript Domain: Conditional Types The issue relates to conditional types labels Oct 26, 2018
@sheetalkamat sheetalkamat added this to the TypeScript 3.3 milestone Dec 8, 2018
@ahejlsberg
Copy link
Member

This is working as intended. We generally don't reason about assignability of conditional types applied to generic types. For this reason, neither this nor AddWith<this, TAlsoWith> is considered assignable to the other, so the assertion fails. In order for the code to type check you'll need to assume responsibility for verifying the assertion by first converting to any:

return this as any as AddWith<this, TAlsoWith>;

@ahejlsberg ahejlsberg added Working as Intended The behavior described is the intended behavior; this is not a bug and removed Bug A bug in TypeScript labels Jan 23, 2019
@ahejlsberg ahejlsberg removed this from the TypeScript 3.4.0 milestone Jan 23, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Domain: Conditional Types The issue relates to conditional types Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

4 participants