Skip to content

Template type fails to infer a matchΒ #48430

Closed

Description

@wbt

Bug Report

πŸ”Ž Search Terms

Template literal type narrowing fails string 2345

πŸ•— Version & Regression Information

  • This changed between versions 4.0.5 and 4.1.5 because that is when the feature was introduced.

⏯ Playground Link

Playground link with relevant code

πŸ’» Code

type EventName<T extends string> = `${T}Changed`; //From feature announcement: https://github.com/microsoft/TypeScript/pull/40336
const functionRequiresEventString = function(narrowedString: EventName<string>) {
	console.log('The following string is an event string per the original example: ' + narrowedString);
}
const nameEvent = function(whatChanged: string) {
	functionRequiresEventString('Functionality Changed');
	//Next line fails: Argument of type 'string' is not assignable to parameter of type '`${string}Changed`'.ts(2345)
	functionRequiresEventString(whatChanged + 'Changed');
}

πŸ™ Actual behavior

Error: Argument of type 'string' is not assignable to parameter of type '${string}Changed'.ts(2345) (but with backticks inside the quotes in the type).

πŸ™‚ Expected behavior

No error: The concatenated string ends in 'Changed' and should pass typechecking.

Related Issues

This is a minimal example using the first example of what should be supported, from the feature announcement, so I don't think reporting an issue in the announced functionality is a duplicate of this issue looking for gaps in what that didn't cover, and that thread is now being ignored anyway. This looks a lot like this issue reported 9/1/20 as a comment on the merged PR but is simpler than this issue around numbers. It’s also simpler than what this commenter sought around a fixed prefix.

Activity

  1. whzx5byb commented on Mar 25, 2022

    @whzx5byb

    Concatenation with + won't produce a template literal type. You must use template strings like functionRequiresEventString(`${whatChanged}Changed`)

  2. wbt commented on Mar 25, 2022

    @wbt
    Author

    whzx5byb Thanks for the helpful reply. I think it mainly calls out a shortcoming in the minimal example above.
    A slightly more realistic case that can't be covered by that is here:

    type EventName<T extends string> = `${T}Changed`; //From feature announcement: https://github.com/microsoft/TypeScript/pull/40336
    const functionRequiresEventString = function(narrowedString: EventName<string>) {
    	console.log('The following string is an event string per the original example: ' + narrowedString);
    }
    const ensureEventName = function(stringIn: string) : EventName<string> {
    	if(stringIn.endsWith('Changed')) {
    		return stringIn;
    	} else {
    		return `${stringIn}Changed`;
    	}
    }

    On the line return stringIn there's an error that this variable isn't assignable to that narrower string type.

  3. whzx5byb commented on Mar 25, 2022

    @whzx5byb

    wbt

    The return type of endsWith is not a type predicate, so it doesn't narrow type as you expected. Related: #46958

  4. wbt commented on Mar 26, 2022

    @wbt
    Author

    Thanks for the reply; this does look like it boils down to a combination of the comment above and #46958, both of which are unexpected. I'll use casting as a workaround.

  5. 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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions