How to write a string type that does not contain an empty string in TypeScript

Viewed 5765

A function of TypeScript wroten as below:

function propKeyMap(propKey:string):string {
  //TODO
}

The propKey can't be an ""(empty string). Can we write a type which does not contain an empty string?

2 Answers

Solution using template literal types

Since TypeScript 4.1 you can achive this using template literal types. However, it's a bit verbose, because you have to define a union type of all possible strings of length 1:

type Character = 'a' | 'b' | 'c' | ...;
type NonEmptyString = `${Character}${string}`;

Solution using conditional types

There's another solution (prior to 4.1) too using conditional types and a generic:


type NonEmptyString<T extends string> = '' extends T ? never : T;
function propKeyMap<T extends string>(propKey: NonEmptyString<T>): string {
  //TODO
}

This solution is useful for functions as you don't have to explicitly specify the generic when calling it. However, when using it anywhere else you'd have to define the generic which then will just make it the same type you use for the generic:

let x: NonEmptyString<'foo'>; // This is of type 'foo'
let y: NonEmptyString<string>; //This is of type never

Likewise, it is not possible to pass a string to the function (which is correct, as string includes an empty string). But this fact, combined with the lack of possibility to type variables as NonEmptyString, means, that this is only useful for functions that will directly be called with string literals rather than variables.

propKeyMap('foo'); // Compiles (as expected)
propKeyMap('');    // Errors   (as expected)

const x: 'foo' = 'foo';
propKeyMap(x);     // Compiles (as expected)

const y: string = 'foo';
propKeyMap(y);     // Errors   (unexpected)

For cases where this limitation is acceptable, I'd recommend this solution though, as it doesn't include defining the cumbersome union type required fo the first solution.

Related