Explain Codes LogoExplain Codes Logo

Set type for function parameters?

javascript
type-checking
javascript-features
best-practices
Alex KataevbyAlex KataevΒ·Aug 24, 2024
⚑TLDR

Choose TypeScript for typed function parameters which can set the parameter types directly in your function. This means sound type safety.

Example:

function add(num1: number, num2: number): number { return num1 + num2; // 'cause maths rock, ya know! 🀘 }

Our function add now strictly requires two number parameters.

Beyond TypeScript, there are other techniques you can consider for type safety and clarity of code. Let's explore them.

Getting hands-on with Type Checking Libraries

PropTypes - your guardian angel for React

In the world of React, we rely on PropTypes for type-checking props. Similarly, it can check the type of function parameters.

function greeting(name) { console.log(`Hello, ${name}!`); } greeting.propTypes = { name: PropTypes.string.isRequired, // Else our greeting might sound a bit off! πŸ‘½ };

Creating your Type guards

Without a library like PropTypes, you can jump into the levitating train of custom type-checking functions:

function checkNumber(value) { if (typeof value !== 'number') throw new Error('OMG, you gotta give me a number!'); // Well, that escalated quickly! 😬 } function multiply(a, b) { checkNumber(a); checkNumber(b); return a * b; // and there was light! 🌞 }

These functions ensure runtime validations, so no more nasty surprises because of the wrong types.

Light up your code with JSDoc

JSDoc for efficient annotation

With JSDoc comments, your code talks to you about its expected types and automatically enhances the developer experience:

/** * Adds two numbers. * @param {number} num1 - The first number to be added. * @param {number} num2 - The second number, because we can't just add one number, right! 😝 * @returns {number} The sum of num1 and num2. */ function add(num1, num2) { return num1 + num2; }

With IDEs such as Visual Studio Code that parse JSDoc, your development process becomes as fun as eating pie (3.1415) πŸ₯§, providing auto-completion and type checks without screaming for TypeScript.

Destructuring - a good "first aid" for objects

When parameters are objects, destructuring shows what's really inside the box:

/** * OK Bob! So what we need is: * @param {{ name: string, age: number }} userProfile - Pass the user's name and age. Speak now or forever hold your peace! */ function createUser({ name, age }) { // Can't wait to see what Bob will bring in. 🎁 }

The destructuring ensures you understand the structure while making the code more readable.

More ways to wrangle types

Google Closure Compiler - the overseer

Not fond of TypeScript? Google Closure Compiler's type annotations feel just at home in the wild world of JavaScript:

/** * It's subtracting time, folks! Let's dig in... * @param {number} num1 Our "minus", the number getting reduced. * @param {number} num2 The "subtractor", the piece of the pie we're cutting out. * @return {number} Here's your pie... or what's left of it! πŸ˜‚ */ function subtract(num1, num2) { return num1 - num2; }

By turning on the advanced mode of Google Closure Compiler, your JavaScript code turns into an Iron Man suit, with type safety included.

Facebook's Flow - the savior

Another savior in our type-checking crusade is Flow from Facebook:

// @flow function divide(x: number, y: number): number { return x / y; // Time for some slice and dice! πŸ• }

Install Flow, run it against your code, and voila, type mismatches are now gotchas! Parentheses make sure you are doing arithmetic, not acrobatics.

Out-of-the-box Typing

Play with types

We can sometimes play with type casting when we can’t enforce a strict data type:

function logLength(value) { let stringValue = String(value); // Turning things to strings has never been easier! console.log(stringValue.length); }

Ensure that the operations you want are performed on your own terms.

Boomerang with a typedFunction

You can encapsulate type-checking within a typedFunction to keep your code neat and type-safe:

function typedFunction(types, func) { return function(...args) { types.forEach((type, index) => { if (typeof args[index] !== type) { throw new TypeError(`Argument ${index} must be of type ${type}. Else, it's a no-go! πŸ™…β€β™‚οΈ`); } }); return func(...args); }; } const safeAdd = typedFunction(['number', 'number'], add); // Now, that's one tough cookie! πŸͺ

You've now rolled out a red carpet for systematic type enforcement.