Title: TypeScript: non-zero number
Tags: typescript
Question: I'm trying to figure out if there is a way to set up a type in TypeScript that reflects a non-zero number:
type Task = { id: number };
const task: Task = { id: 5 };
const tasks: { [taskId: number]: Task } = { 5: task };
function getTask(taskId: number | undefined): Task | undefined {
return taskId &amp;&amp; tasks[taskId];
Playground here
In the above code, TypeScript complains that because taskId is a number, it could be 0, which is falsey, so the function would return 0 rather than a Task or undefined. Practically speaking, it is impossible for a task id to be 0. It will always be a positive integer, so that case is not an issue. Is there a way to declare the Task type to indicate to TypeScript that this number will never be falsey? I'd rather avoid extra conditional logic to convince TypeScript.
Comment: No, not possible. https://stackoverflow.com/questions/51442157/type-for-every-possible-string-value-except. But you could use overloads to solve this https://www.typescriptlang.org/play?#code/C4TwDgpgBAKghgZwNZQLxQN5QJYBMBcUAdgK4C2ARhAE5QC+A3AFADGA9kQsFMIkofGRpMOAlACs9Zu07deyBISwBteUgCSY0pRoBdAX3rCs4wmqlMmAMxJEWwbBygBzCMEFIAFGs2EADACUhEQQAG401rb2jkQubh7efL5QtrgQVtghuEEpRGkZWZF2Dk6u7nyJyMnaVNQ5HkXRpfEVPrgA-MHktQGYTFADUNRuJNSxbVAAZJM8fAiqSbi6zHSWMlw8fsJlCYGsHBvAAKp56ZkQuNstyJ6pZ1kB+7I8AIxX5TcvgUA

Comment: Another option: `return taskId && tasks[taskId] || undefined;`

Comment: why don't you use a simple array instead of a hashmap, whose keys are numbers?


Here is another answer: There's no way for typescript to guarantee that there will be a task for any possible taskId.
There are a few options here:
use the non null assertion operator to inform typescript that you know better and are sure the task will always exist
constrain the type to be the set of possible taskId by defining them as an enum or similar
check that the task exists and throw an exception if it is undefined
Assuming that your set of tasks is dynamic, I would personally go for the last option, eg:
function getTask(taskId: number): Task {
const task = tasks[taskId]
if(!task){ throw new Error(`task with id ${taskId} does not exist`) }
return task
As this will give you a useful error if your invariant is violated.
Comment for this answer: The question here isn't whether there is a task, but whether the `taskId` will be `0`. `taskId` might be `undefined` or there might not be a task, which is fine, but I'm trying to convince TypeScript that it won't be `0`, which is falsey.

{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 1, 'CommentCount': 3, 'ContentLicense': 'CC BY-SA 4.0', 'CreationDate': '2020:00:11/14/20', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<typescript>', 'Title': 'TypeScript: non-zero number', 'ViewCount': 950, 'id': 64831022, 'user_AboutMe': '', 'user_AccountId': 155667.0, 'user_DisplayName': 'lobati', 'user_Reputation': 8238.0, 'user_Views': 319.0, 'user_id': 372479.0}}