Testing Hoisting with Jest: A TypeScript Challenge
Hoisting is a JavaScript behavior where variable and function declarations are conceptually moved to the top of their scope before code execution. While seemingly abstract, understanding hoisting is crucial for debugging and writing predictable code. This challenge asks you to create Jest tests to verify that hoisting behaves as expected in a TypeScript environment, specifically focusing on variable and function declarations.
Problem Description
You are tasked with writing a suite of Jest tests to confirm that hoisting works correctly in a TypeScript file. The tests should cover the following scenarios:
- Variable Hoisting (var): A variable declared with
varshould be accessible before its declaration line, even though it will initially have a value ofundefined. - Variable Hoisting (let/const): Variables declared with
letorconstshould not be accessible before their declaration line. Attempting to access them should result in aReferenceError. - Function Declaration Hoisting: Function declarations (not function expressions) should be accessible before their declaration line.
- Function Expression Hoisting: Function expressions should not be accessible before their declaration line. Attempting to call them should result in a
TypeError(cannot read property '...' of undefined).
Your tests should use expect assertions to verify the expected behavior in each scenario. The tests should be written in TypeScript and utilize Jest's features for asynchronous testing if necessary (though hoisting itself is synchronous).
Examples
Example 1: Variable Hoisting (var)
Input:
// hoisting.ts
var hoistedVar = "Hello";
console.log(hoistedVar);
Output:
"Hello"
Explanation: Even though `console.log(hoistedVar)` appears before the declaration of `hoistedVar`, hoisting moves the declaration to the top of the scope, so the variable exists (with a value of `undefined` initially, but then assigned "Hello").
Example 2: Variable Hoisting (let/const)
Input:
// hoisting.ts
console.log(letVar); // Attempt to access before declaration
Output:
ReferenceError: letVar is not defined
Explanation: `let` and `const` are not hoisted in the same way as `var`. Attempting to access them before their declaration results in a `ReferenceError`.
Example 3: Function Declaration Hoisting
Input:
// hoisting.ts
myFunction();
function myFunction() {
console.log("Function called!");
}
Output:
"Function called!"
Explanation: Function declarations are hoisted to the top of their scope, allowing them to be called before their physical declaration.
Example 4: Function Expression Hoisting
Input:
// hoisting.ts
myFuncExpression();
var myFuncExpression = function() {
console.log("Function expression called!");
};
Output:
TypeError: Cannot read properties of undefined (reading '...')
Explanation: Function expressions are not hoisted like function declarations. The variable `myFuncExpression` is hoisted, but its value is `undefined` until the assignment. Attempting to call `undefined` results in a `TypeError`.
Constraints
- The TypeScript file being tested (
hoisting.ts) should be a single file. - All tests must be written in TypeScript.
- The tests should be self-contained and not rely on external dependencies beyond Jest and TypeScript.
- The tests should accurately reflect the expected hoisting behavior as described above.
- The tests should be readable and well-documented.
Notes
- Consider using
expect(() => { ... }).toThrow(ReferenceError)andexpect(() => { ... }).toThrow(TypeError)to assert that specific errors are thrown. - Think carefully about the order in which you access variables and functions within your tests to properly demonstrate hoisting.
- Remember that hoisting is a conceptual model; the code is not literally moved. The JavaScript engine processes declarations differently.
- Focus on testing the behavior of hoisting, not the underlying mechanism.
- You will need to create a
hoisting.tsfile with the code to be tested. Your Jest tests will then import and test this file. You can userequireorimportstatements.