'Understanding TypeScript template literal type with `${any}${any}`

Can someone explain why this:

type NotEmpty<T extends string> = T extends `${any}${any}` ? T : never;

declare function something<T extends string>(x: NotEmpty<T>): void;

something("hello")
something(""); // Argument of type 'string' is not assignable to parameter of type 'never'.(2345)

achieves the obvious goal of the type and yet this does not:

type NotEmpty<T extends string> = T extends `${string}${string}` ? T : never;

declare function something<T extends string>(x: NotEmpty<T>): void;

something("hello")
something(""); // okay

and also this does not:

type NotEmpty<T extends string> = T extends `${any}` ? T : never;

declare function something<T extends string>(x: NotEmpty<T>): void;

something("hello")
something(""); // okay


Solution 1:[1]

I'm surprised the first one works to be honest: Intuitively, you'd think '' extends string extends any.
¯\(?)

Here's a working type that in case any future person needs one that is straightforward.

type NonEmpty<T extends string> = '' extends T ? never : T;

But this feels like cheating because it explicitly uses empty string and doesn't answer your question.

However, If you expand out either the ${any}${any} or ${string}${string} using infer, they both yield your expected result.

type NonEmpty<T extends string> = T extends `${infer First}${infer Rest}` ?
 First extends string ? Rest extends string ? T : never : never : never;

which only adds to my confusion. I know there are some simplifications to types when it comes to template literals. I think the best path to an answer would be to open an issue on the Typescript repo and hope that Anders (the Typescript guy) or someone on the team clarifies.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ballmerspeak