Like @Alex said, it doesn't seem to be possible with current TS. However, you can do something similar for a function parameter:
type TestName = 'test1' | 'test2' | 'test3';
type NotTestName<T> = T extends TestName ? never : T;
function myFunc<T>(myValue: NotTestName<T>) {}
Now, the key part on calling this function is to ensuring you get the value narrowed as string
is, indeed, not in the TestName
type and, therefore, it would pass the test:
// Allowed
myFunc('test' as const);
myFunc('abc' as const);
// Not allowed
myFunc('test1' as const);
myFunc('test2' as const);
myFunc('test3' as const);
Ultimately, if you need a final const value like in your post, you can use it as helper function:
type TestName = 'test1' | 'test2' | 'test3';
type NotTestName<T> = T extends TestName ? never : T;
function h<T>(value: NotTestName<T>): T { return value; }
// Allowed
const name = h('test' as const);
// Not allowed
const name = h('test1' as const);
const name = h('test2' as const);
const name = h('test3' as const);
You can run it in this playground.
Remember that if the string is not narrowed, you will get the test to wrongly pass.