Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
975 views
in Technique[技术] by (71.8m points)

typescript - Type for non-false, aka truthy

In TypeScript, is there a type for truthy?

I have this method: Object.keys(lck.lockholders).length; enqueue(k: any, obj?: any): void think with TS there is a way to check for empty strings '', by the way. and I want to convert it to:

  enqueue(k: Truthy, obj?: any): void

except I don't know how to define the type for Truthy. I think with TS there is a way to check for empty strings '', by the way.

The reason I want this is that I don't want users to pass in null, undefined, '', etc, as the key to a hash.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

I'm not sure why you need this but it's interesting. In all honesty the short answer is: TypeScript isn't geared for this and you'd probably be better off doing runtime checks and documenting your code so that developers are aware that the k param should be truthy. Still, if you're set on trying to force TypeScript to do something like this, read on:


Note: for the below to work, turn on the strictNullChecks compiler option. It's kind of necessary, since being unable to distinguish Truthy from Truthy | null | undefined would be a problem.

You can almost define falsy, which is like

type Falsy = false | 0 | "" | null | undefined 

except NaN is also falsy, and TypeScript doesn't have a numeric literal for NaN (see microsoft/TypeScript#15135).

Even if you have Falsy as above, there are no negated types (see microsoft/TypeScript#4196) in TypeScript, so there's no way to express Truthy as "everything but Falsy".

You could try to use use conditional types to exclude possibly-falsy parameters in enqueue(), but it is weird:

type DefinitelyTruthy<T> =
  false extends T ? never :
  0 extends T ? never :
  "" extends T ? never :
  null extends T ? never :
  undefined extends T ? never :
  T

declare function enqueue<T extends number | string | true | object>(
  k: T & DefinitelyTruthy<T>,
  obj?: any
): void

declare const str: string;
enqueue(str); // error, might be falsy
enqueue("a"); // okay
enqueue(1); // okay
enqueue(0); // error
enqueue(NaN); // error
enqueue(true); // okay
enqueue(false); // error
enqueue([]); //okay
enqueue({a: "hello"}); // okay
enqueue({}); // error, interpreted as type {} which could be an empty string:
const zilch = "" as {};
enqueue(zilch); // error, see? 

Note how it won't allow anything which it thinks might be falsy, which is possibly what you are trying to achieve. Can't tell.


Update

I see you edited the question to clarify that the k parameter should really be a string (or possibly a symbol) and that the only value you need to exclude is the empty string "". In that case you could simplify the above to:

type DefinitelyNotEmptyString<T> = "" extends T ? never : T

declare function enqueue<T extends string | symbol>(
  k: T & DefinitelyNotEmptyString<T>,
  obj?: any
): void

enqueue(""); // error
enqueue("a"); // okay

All of that is great, but unfortunately there's the problem that if you pass a general string to enqueue() it will fail, and sometimes a developer might need to do that if the value they are using for the k parameter isn't a string literal they have specified:

declare const str: string; // comes from somewhere else
enqueue(str); // error!  how do I do this?

To deal with this, you can try to create a nominal type which you can use to identify to the compiler that a value has been checked for emptiness, and then make a user-defined type guard to constrain a string to that type:

type NotEmptyString = string & {"***NotEmptyString***": true};
function notEmptyString(x: string): x is NotEmptyString {
  return x !== "";
}

Now the developer can do this:

declare const str: string;
enqueue(str); // error, might be falsy
if (notEmptyString(str)) {
  enqueue(str); // okay, str is NotEmptyString
}

Whew! That's a lot of hoop jumping. It's up to you if you think this is worth it. Okay, hope that helps. Good luck!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...