DEV Community

150+ Typescript one-liners [code snippets].

Christian Prado Ciokler on July 24, 2022

OneLiners OneLiners are short snippets of code that are used in many places in the codebase. This is a collection of 150+ one-liners wri...
Collapse
 
joelbonetr profile image
JoelBonetR πŸ₯‡ • Edited

Hi Christian,

As advice, take care when using TS. It sets you in a peace of mind state, thinking that you'll be available to set only the types you defined for each property but that's not how it works.

If you set

export const isEmpty = <T, \_>(arr: T[]): boolean => Array.isArray(arr) && !arr.length;
Enter fullscreen mode Exit fullscreen mode

in a package, lib or js SDK, other software will still be capable of sending 'non expected' data into it and it's not protected or workarounded to ensure the reliability:

The transpiled to JS version will look like that:

export const isEmpty = (arr) => Array.isArray(arr) && !arr.length;
Enter fullscreen mode Exit fullscreen mode

in which case:

isEmpty();  // false
isEmpty('') // false
isEmpty(null) // false
isEmpty(undefined) // false
Enter fullscreen mode Exit fullscreen mode

The reason is that Array.isArray(arr) evaluates into false thus returning false directly and the short circuit AND operator is not evaluated.

Some cases like that leads you to avoid one-liners for good:

const isEmpty = (arr) => {
    if(Array.isArray(arr)) return !arr.length 
    else throw `isEmpty error, Array expected but found ${typeof arr}`;
}
Enter fullscreen mode Exit fullscreen mode

Now you can translate that into TS if you want but it just doesn't matter, either it beign JS or TS, it will be reliable and not depend on the target devs to use TS as well (which of course still won't cover API responses and so unless you specificaly typecheck them etc...).

Cheers!

Collapse
 
htho profile image
Hauke T.

Nice collection.

Please carefully edit your code snippets:

  • there are asterisks (*) prefixed with a backslash (\) and there are underscores (_) where there should be asterisks.
  • some array functions have a second generic type named underscore (_) some of these underscores are prefixed with a backslash (\)
  • there is a list of Month names, where "November" has leading whitespace

If I read these code-snippets and see those "mistakes" I don't know if I should trust these.

Collapse
 
chrisciokler profile image
Christian Prado Ciokler

Thank you for spotting those errors. I'll fix them right away.
Some kind of error with the markdown at the time I pass it.

Collapse
 
htho profile image
Hauke T.

Thanks.

Whats up with those underscore generics I can't see their purpose?

Collapse
 
joelbonetr profile image
JoelBonetR πŸ₯‡ • Edited

Hi Luke,
I'll try to answer your questions or points one by one below

I prefer his isEmpty because I will not have to wrap it in a try/catch like yours

it is not a try catch, it is a throw, which is meant to articulate user-defined exceptions.

It is used as "offensive programming" tool and it should be used whenever defensive programming doesn't fit in the specific use-case.

Read more about defensive and offensive software design.
A bit excerpt from that:

Generally speaking, it is preferable to throw exception messages that enforce part of your API contract and guide the developer instead of returning error code values that do not point to where the exception occurred or what the program stack looked liked, Better logging and exception handling will increase robustness and security of your software, while minimizing developer stress.

As extra info, a try...catch statement will only reach the catch if any Exception occurred inside the try execution block. It can be either a language pre-defined exception or a user-defined one (using throw).

You should use try...catch when calling functions that throw errors and maybe using the finally optional statement to ensure defensive programming if it suits.

Example:

  /**
   * Selects a row from User model by primary key
   * @param {number} userId 
   * @returns {Array<any>}
   */
  const getUserData = (userId) => {
    if (typeof userId !== number) throw `getUserData Error. Number expected but found ${typeof userId}`;

    return await Users.find({id: userId});
  };

  /**
   * Gets information about a given user by ID
   * @param {number} userId
   * @returns {Array<any>}
   */
  const getUserInformation = (userId) => {
    let info = [];
    try {
      info = getUserData(userId);
    } catch (err) {
      console.error(`getUserInformation Error. ${err.message} in ${err.stack}`);
    } finally {
      return info;
    }
  };
Enter fullscreen mode Exit fullscreen mode

You'll notice that getUserData handles it's own exceptions (as it should be) and that, the caller ( getUserInformation in this case) has a try...catch.
If you send a string into it, it will try to call getUserData with this string and getUserData will throw an exception to the caller, that will be captured by the catch statement.

In this case we apply both offensive and defensive programming designs. Notice that getUserInformation will always return an Array, either be empty or filled in with the data of that given user from the DB.

In this case it may be useful to use

const userControllerExample = (user) => {
  if (isEmptyArray( getUserInfo( user.id ) ) ) throw `userControllerExample Error. No data was found searching for user ${user.id}`;
}
Enter fullscreen mode Exit fullscreen mode

and so on.

Hope now you find it as useful as it is IRL.

The idea of using TypeScript is that folks will get an error in dev time when trying to pass something to isEmpty that isn't an array, so they'll not be able to do isEmpty() or isEmpty(null) because they'll get compilation errors.
Even if the people using your lib is not using TS, they still get the type checking benefits (red underline when they pass something that isn't valid).

You may need several manual hard work to reach that, specially when dealing with different microservices.

If you receive a string or a undefined on a property after an API Call (in runtime, of course) when you expect an Array, either be by any mistake on the other side or by lack of data, and you try to pass isEmpty( myResponse.info ) you may get one of those:

isEmpty(undefined) // false
isEmpty('') // false
isEmpty(null) // false
Enter fullscreen mode Exit fullscreen mode

And the purpose of the function isEmpty() is now missleading and useless, sending the issue to the next function in the stack:

if( !isEmpty( myResponse.info ) getPreferences( myResponse.info );
Enter fullscreen mode Exit fullscreen mode

So if myResponse.info is undefined, an empty string, null... you will get false, thus send this "allegedly non-empty value" to getPreferences, in which you'll get a weird runtime error like that Uncaught TypeError: Cannot read properties of undefined.

If you're objective here, you'll see that the isEmpty function is not exactly doing what anyone would assume it does.

The compiled code will be unnecessarily longer with that throw on it. Not to mention the error isn't localized as a type error could be on the IDE.

It's the responsibility of the engine to handle that and optimize it, not ours. As devs we need to ensure there are no errors in runtime as well and, in case any bug appear, we should provide the tools to find the origin of the issue as fast as possible.

Don't build software thinking on how the engine will interpret and handle it. There are good reasons for that:
1- There are more than a single JS engine (V8, Spidermonkey, webkit) and there are differences as well between V8 in Node than V8 in Deno to set some examples.
2- It may change at any time without notifying you. Any design flaw, optimization path or performance increase the maintainers of each engine find during their job will be prioritized, developed, merged and set into production and they may or may not set the details publicly.

If you still think is a better option to throw, then why are you even using TypeScript?

You should also use Throw along TS. Check the advanced types reference, specifically type guards.

I'm copying the example in TS doc for convenience:

function padLeft(value: string, padding: string | number) {
  if (typeof padding === "number") {
    return Array(padding + 1).join(" ") + value;
  }
  if (typeof padding === "string") {
    return padding + value;
  }
  throw new Error(`Expected string or number, got '${padding}'.`);
}
Enter fullscreen mode Exit fullscreen mode

It's just that in this specific use-case you'll be good either with TS or without it. You can also set JSDoc instead:

  /**
   * Checks whether an Array is empty or not
   * @param {Array<any>} arr
   * @returns {boolean}
   */
  const isEmptyArray = (arr) => {
    if (Array.isArray(arr)) return !arr.length;
    else throw `isEmpty error, Array expected but found ${typeof arr}`;
  };
Enter fullscreen mode Exit fullscreen mode

And the result will be the same adding compatibility with any TS project.

Don't get me wrong, I still don't think the isEmpty function is perfect, it could use a rename, and better generics:
export const isEmptyArray = ({ length }: ArrayLike) => length > 0;

This won't prevent it to evaluate undefined.length and throw Uncaught TypeError: Cannot destructure property 'length' of 'undefined' as it is undefined.

We got plenty of tools in programming language APIs and the major part of them implement try...catch and exceptions for good reasons (except from some "low level" languages such C in which there are no Exceptions, if you're curious about that I'm letting a paragraph below).

The first step is to learn the tools, then discern whether to use them and then use them. You'll become a better developer each time you learn something new during this process. 😁


In C, the errors are notified by the returned value of the function, the exit value of the process, signals to the process (Program Error Signals (GNU libc)) or the CPU hardware interruption (or other notification error form the CPU if any), for example, see How processor handles the case of division by zero. You still can handle some sort of exception-like manually using setjmp.h.

Collapse
 
moopet profile image
Ben Sinclair

A lot of these are pretty dangerous.

Not because they're wrong, necessarily, but more because they're "one-liners" in the same way that people's "pure CSS" drawings are done in pure CSS.

When you get to the point of having a "one-liner" that's 348 characters long, you have to consider getting a wider monitor. Like, a 65" wide monitor. Otherwise, you're going to wrap. And you know where you're going to wrap? At the points where you would reasonably be expected to have had a line break.

You can take any application and minimise it to one line if you want, you can make the variable names terse and impenetrable, you can exclude guard clauses and make assumptions about things other than just types, but it doesn't make good code.

There's nothing wrong with these ideas, but why force them onto one long, long, unreadably-long line for the sake of a catchy post title?

"Short, re-usable Typescript snippets" would describe them just as well then.

 
joelbonetr profile image
JoelBonetR πŸ₯‡ • Edited

I agree with almost everything you said except for the usefullness of controlled errors.
I've updated the comment before to add an example on how it should be used.

It is better to control which errors can happen (not necessarily type errors) and being able to defensively control what the function will return so the software execution doesn't stop by that error, than having your software broke in production for some minutes because "cannot read property x from undefined" or things like that.

The only folks I know that like code that throws work with Java. Everyone else I know hate code that throws...

It's not a matter of like or dislike, those are tools that the language implements and are usefull in every single software you may write. Disliking them won't make them less usefull πŸ€·β€β™‚οΈ

Error recovery is an important point when giving service to customers and/or third parties (basically always). throw along with try...catch gives you a more detailed information about what went wront, where it happened and the data passing through that specific point that caused the exception. Thus providing shorter debug times, faster hotfixing, faster new devs handover, lets you to register meaningful logs, increases the reliability of the software and makes you curstomers happier about the product by the use of finally or other defensive programming designs so they can keep working with the rest when a feature is broken.

Has it ever happened to you that you are playing some videogame and it suddenly breaks to an unhandled exception? Specially in this situation where you forget to save your game for about an hour... This is how your customers feel when the software breaks to an unhandled error when working/using it.

In such situation either you blame the game or the publisher (if you don't have software dev skills) or you blame that moron dev that forget to scope it's code inside a try...catch and set a recovery path for that error.
When we are developing, that moron could be us if we forget about that important part πŸ˜…

 
joelbonetr profile image
JoelBonetR πŸ₯‡

I'll do it for sure, thank you for your comments, much appreciated! I'll start a new project in september so as I'm the one choosing the stack and designing the implementation thingy I may take a try 😁

Btw I've sent you a connection request through LinkedIn (unless someone else stole your name πŸ˜…).

 
joelbonetr profile image
JoelBonetR πŸ₯‡ • Edited

Hahaha gosh it's the first time I read anyone mentioning this in this community.

While this could be a good approach (it is mentioned in my comment before about defensive programming on a different way if you check the link) if the language itself is not applying this "way to work" it will eventually fail (mostly by human error, like the major part if not all bugs we encounter).

It has nothing to do with FP and it's more about the implementation of a given language and how you code with it.

I like defensive programming a lot, still I'm mainly a JS dev (since some years ago) and I'm aware that the language is not implemented like Elm. I'm also aware that I've juniors in the team I manage on almost every project and I need to set up realistic boundaries for them to code in.

Even you code in that way, you can face an error pretty easily when dealing with the own language API as the pre-defined methods of the language will throw errors for sure that, if not controlled, will break your software in runtime.

It is what it is, not what we would like to have πŸ€·β€β™‚οΈπŸ˜…πŸ˜‚

Collapse
 
retr0ville profile image
Retroville

Do these exist in a Git Repo you can link?

Collapse
 
chrisciokler profile image
Christian Prado Ciokler

Is a work in progress but you should find all the liners.

github.com/chrisciokler/typescript...

Collapse
 
retr0ville profile image
Retroville

This is great, thank you.