I am looking to streamline the process of deriving a new union from an existing one, without having to explicitly state the string as a parameter each time. The goal is to extract all root strings that end in .bar
from a union of translation key strings like this:
type Keys = 'foo.bar' | 'baz.bar' | 'fail.error';
An example desired output for the above union would be 'foo' | 'baz'
My current solution involves using generics to achieve this, but it requires manual input of the string as a parameter:
type Namespace<T extends string = string> = `${T}.bar` extends Keys ? T : never;
const example0: Namespace<'foo'> = 'foo'; // Works, but needs explicit typing
const example1: Namespace<'notFound'> = 'notFound'; // Produces an error as expected
However, I am looking for a more efficient way to define and use this type, where I don't have to specify the string parameter each time:
const example2: Namespace = 'foo'; // Should work without providing the type
const example3: Namespace = 'baz'; // Should also be allowed
const example4: Namespace = 'fail'; // Expected to throw an error
const example5: Namespace = 'notFound'; // Should result in an error
If there is a better approach to achieving this type, I would greatly appreciate any suggestions.