0

If I have a type as:

type TestName = 'test1' | 'test2' | 'test3';

How do I define a type of string with not the above?

type CustomName = `${string}` /// need to exclude TestName

const name: CustomName = 'test'; // allowed
const name: CustomName = 'test1'; // not allowed
const name: CustomName = 'test2'; // not allowed
const name: CustomName = 'test3'; // not allowed
Ewan
  • 378
  • 3
  • 14
  • This isn't possible, as NOT types are not currently expressible in TypeScript. You can however, write a function to infer and validate its argument: https://tsplay.dev/NnlKxW – kelsny Feb 13 '23 at 16:18
  • For reference this is called a negated type and is currently experimental https://github.com/Microsoft/TypeScript/pull/29317 – Alex Feb 13 '23 at 16:27
  • ^ It's not just "experimental", it's closed and isn't going to be merged. Maybe we'll have negated types in the future but it probably won't be coming from that pull request. – jcalz Feb 13 '23 at 20:53

1 Answers1

0

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.

carlosV2
  • 1,167
  • 6
  • 15
  • What as const is for, in this case ? – Romain TAILLANDIER Feb 14 '23 at 08:01
  • Take a look at this [SO answer](https://stackoverflow.com/questions/66993264/what-does-the-as-const-mean-in-typescript-and-what-is-its-use-case) it explains it better than I would. Using plain words and for this particular case, it is telling TS "consider this value as a literal value instead of as a string" thus narrowing it's type. – carlosV2 Feb 14 '23 at 08:16