49

Is there a way for TypeScript to statically check for an empty string? Is there a way to statically require a non-empty string to be passed to a function?

let fn = function(a:string){

};

fn('');

or

let a = '';
fn(a);

Can TS help us here?

7 Answers 7

37

I believe this is as close as you're going to get only using the typing system (rather than having a 'nonEmptyString' class)

type nonEmptyString = never; // Cannot be implicitly cast to
function isNonEmptyString(str: string): str is nonEmptyString {
    return str && str.length > 0; // Or any other logic, removing whitespace, etc.
}

Testing it:

let fn = function(a: nonEmptyString) {

}

let someStr = '';
if (isNonEmptyString(someStr)) {
    fn(someStr); // Valid
} else {
    fn(someStr); // Compile error
}

Unfortunately, you end up with warts since nonEmptyString is never. Which means you need to explicitly cast nonEmptyString back to string.

let fn = function(a: nonEmptyString) {
    let len = a.length; // Invalid
    let len2 = (<string>a).length; // Valid
    let str = a + 'something else'; // Valid (str is now typed as string)
}

One possible resolution is:

type nonEmptyString = string & { __nonEmptyStr: never };

Which alleviates the problem of having to explicitly cast back to a string (all three tests above are valid), but does pollute the type with __nonEmptyStr (which will be undefined if referenced).

Sign up to request clarification or add additional context in comments.

4 Comments

maybe we could require an object with a toString method, that also would work, just a different type of solution.
Except I think all objects have a toString method...hmm.
Why not just use the string type then: const isNotBlank = (str?: string|null): str is string => (str !== undefined && str !== null && str.trim().length > 0)? Genuine question - what would be wrong with this approach?.
@Anoiny That works for checking if it's not empty, but how would you use that to define a function which required a non empty string?
29

You can use this trick in your specific case:

function fn<T extends string>(a: T extends '' ? never : T) {
  // But TypeScript won't know here that !!a === true
}

fn(''); // Error
fn('foo'); // No error

Note that this does NOT work when passing a variable that has type string:

const myEmptyString: string = '';

fn(myEmptyString); // Should error, but does not

3 Comments

The only right answer for the question. It totally works and doesn't involve static type checking.
Is there any way to do this for an interface rather than function params? e.g. ``` type NonEmptyString = ....; interface Props { content: NonEmptyString; } ```
you can turn this into a utility type type NonEmptyString<T> = T extends '' ? never : T
3

You could maybe type it with overloads such as to give a bad return type on "" that will make things error as soon as you use it elsewhere:

type MyFnType = {
  (a: "") => never;
  (a: string) => whatever;
}

function fn: MyFnType = ...

2 Comments

for some reason, the above syntax is not compiling , but I agree with the solution
This solution works, but as already noted this example won't compile. Here is an example that will: codesandbox.io/s/jnbu6 – it does function overloading e.g. function fn(s: ''): never; function fn(s: string): string; function fn(s: string | '') {/* do the real work here *}
3

Workaround

type NonEmpty<T extends string = string> = T extends '' ? never : T
// or extends NonNullable
type NonNull<T> = T extends string ? NonEmpty<T> : NonNullable<T>

Note! It only works with Literal Types and Generic Type, not works with Primitives Type string.

playground

2 Comments

In fact, if I don't consider historical factors, I prefer to name NonNull as Valuable.
but const foo: NonEmpty = '' will result in foo being of type string
1

Using template literal types:

type NotEmptyString = `${any}${string}`;

This is something that just works this way. This works in TS code but you must check values coming from external apis.

Discussion related to ${string}${string} problems is here: https://github.com/microsoft/TypeScript/issues/57233

Comments

-4

You can use !a to check if a is an empty string.

1 Comment

Not an answer, because question is about static type check in TypeScript, not run-time check in JavaScript.
-5

Go to tsconfig.json in your project add this code under "strict":true,

"strictNullChecks": false, it will solve your problem

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.