Skip to content
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

[5.0.2]: const-like inference is not preserved in conditionally requirable intersected object #53320

Closed
conorbrandon opened this issue Mar 17, 2023 · 2 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@conorbrandon
Copy link

Bug Report

πŸ”Ž Search Terms

const-like inference, const type parameter, conditionally require

πŸ•— Version & Regression Information

5.0.2

  • I was unable to test this on prior versions because const type parameters are a new feature

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

type StringWithSpace = `${string} ${string}`;
type FooBar<Foo extends string, Bar extends Record<string, string>> = {
  foo: Foo;
} & (
  Foo extends StringWithSpace // πŸ’‘if changing to simply `Foo extends string`, const-like inference is used
  ? { bar: Bar }
  : { bar?: never }
);
//                                                            ⬇️ use const like inference
declare function requireBarIfFooHasSpace<Foo extends string, const Bar extends Record<string, string>>(foobar: FooBar<Foo, Bar>): Bar;
const foobar = requireBarIfFooHasSpace({
  foo: 'has space',
  bar: {
    hello: 'world'
  }
});
type inferredFooBar = typeof foobar;
//    ^? type inferredFooBar = {␊hello: string;␊}

πŸ™ Actual behavior

Using an extends check to conditionally intersect an object to make a property required or unallowed does or does not preserve const-like inference, depending on the complexity of that check.

If it is a simpler check, such as extending a primitive, const-like inference is used. If it is a check extending a template literal, the inference is lost.

πŸ™‚ Expected behavior

The complexity of the check to conditionally intersect the object should not determine whether const-like inference is used.

Potentially related to #53307

@ahejlsberg
Copy link
Member

This is working as intended. Inference for Foo and Bar happens at the same time, so when determining the contextual type for { hello: 'world' } it is not yet known that the inferred type for Foo will be 'has space'. Therefore, evaluation of the conditional type is based on the constraint of Foo, which is string. Since string doesn't extend StringWithSpace, the resulting type is { bar?: never }. This type doesn't reference a const type parameter, thus no const behavior.

@ahejlsberg ahejlsberg added the Working as Intended The behavior described is the intended behavior; this is not a bug label Mar 17, 2023
@conorbrandon
Copy link
Author

Thank you for the clarification!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

2 participants