Skip to content

infer R extends in template literal does not narrow correctly when extending union of literals #52801

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
ehoogeveen-medweb opened this issue Feb 16, 2023 · 4 comments
Labels
Duplicate An existing issue was already created

Comments

@ehoogeveen-medweb
Copy link

ehoogeveen-medweb commented Feb 16, 2023

Bug Report

πŸ”Ž Search Terms

template literal infer extends union narrowing

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about infer extends in template literals.

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

// Works as expected.
type GetGenericPrefix<Str extends string> = Str extends `${infer pre extends string}${'!' | '?'}` ? pre : '';
type someString = GetGenericPrefix<'foo?'>; // The expected literal type 'foo'.

// Compact, but doesn't work.
type GetKnownSuffix1<Str extends string> = Str extends `${string}${infer suf extends '!' | '?'}` ? suf : '';
type knownSuffix1 = GetKnownSuffix1<'foo?'>; // The union '!' | '?' instead of the expected literal type '?'.

// Works, but not scalable.
type GetKnownSuffix2<Str extends string> =
  Str extends `${string}${infer suf extends '!'}`
  ? suf
  : Str extends `${string}${infer suf extends '?'}`
  ? suf
  : '';
type knownSuffix2 = GetKnownSuffix2<'foo?'>; // The expected literal type '?'.

πŸ™ Actual behavior

Type GetKnownSuffix1 returns the entire extended union ('!' | '?') instead of the matching literal ('?').

πŸ™‚ Expected behavior

Type GetKnownSuffix1 should return just the matching literal ('?'), the same way infer pre extends string in GetGenericPrefix returns the literal type 'foo' and not the extended type string.

@whzx5byb
Copy link

Related: #49839 (comment)

@whzx5byb
Copy link

whzx5byb commented Feb 16, 2023

Workaround: use distribution behavior to simplify the "not scalable" code

type GetKnownSuffix<Str extends string, Suffix extends string> = 
  (Suffix extends infer S extends string
    ? Str extends `${string}${infer R extends S}`
      ? R
      : never
    : never
  ) extends infer T ? [T] extends [never] ? '' : T : never;
    
type knownSuffix = GetKnownSuffix<'foo?', '!' | '?'>
//   ^?  "?"
type knownSuffix2 = GetKnownSuffix<'foo', '!' | '?'>
//   ^?  ""

Playground

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Feb 17, 2023
@RyanCavanaugh
Copy link
Member

This seems to be a manifestation of the same problem described at #49839 (comment)

@typescript-bot
Copy link
Collaborator

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants