Skip to content

Boolean properties are treated differently in conditional types (functions/methods) #48696

Closed

Description

@bluebarcode

Bug Report

Comparing conditional types containing boolean properties behave dififferent to other property types. But this only occures when the comparison takes place in a function/method.

🔎 Search Terms

conditional types, boolean, method, function

🕗 Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ

⏯ Playground Link

Playground link with relevant code

💻 Code

type FailsType = {
  foo: boolean;
};
type WorksType = { 
  foo: string
};
class TestClass<Param> {
  testFunc: <T extends Partial<Param>>(
    param: T
  ) => {testProp?:Param extends Partial<T> ? 'yes' : 'no'} = (param)=>({});
}
type inlineTest = FailsType extends Partial<FailsType> ? 'yes' : 'no';
const inlineTestValue:inlineTest = 'yes';

// Here i use the Works Type
const testClassWorks = new TestClass<WorksType>();
const resultWorks = testClassWorks.testFunc({ foo: 'works' });
resultWorks.testProp='yes';

// Here i use the Fails Type
const testClassFails = new TestClass<FailsType>();
const resultFails = testClassFails.testFunc({ foo: false });
resultFails.testProp='yes';

🙁 Actual behavior

The type of resultFails.testProp is not 'yes'

🙂 Expected behavior

The type of resultFails.testProp should be 'yes'

Activity

  1. bluebarcode commented on Apr 14, 2022

    @bluebarcode
    Author
    const testClassFails = new TestClass<FailType>();
    const failParam = { foo: false }; // Step between!
    const resultFails = testClassFails.testFunc(failParam);
    resultFails.testProp='yes';

    Interesting enough this works! the "typeof" used in the function seems to be slightly different...

  2. whzx5byb commented on Apr 14, 2022

    @whzx5byb

    It is similar to #48363, which was fixed by #48380. But it seems the PR doesn't fix the issue when a boolean literal is used as a property.

  3. RyanCavanaugh commented on Apr 19, 2022

    @RyanCavanaugh
    Member

    boolean is an alias for true | false, and when a primitive literal is contextually typed by a union containing that literal's corresponding type, then it retains its actual literal type instead of widening to its parent primitive. So the comparison here is { foo: boolean } extends { foo?: false } ? ... which is correctly false

  4. bluebarcode commented on Apr 19, 2022

    @bluebarcode
    Author

    Thank you for the explanation!

    This is not intuitive tho. But i assume there is good reason to be as it is? Especially since when i assign the object literal to a variable before it does indeed work.

  5. typescript-bot commented on Apr 21, 2022

    @typescript-bot
    Contributor

    This issue has been marked 'Working as Intended' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

  6. locked as resolved and limited conversation to collaborators on Oct 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Working as IntendedThe behavior described is the intended behavior; this is not a bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions