14  Deno with Jupyter: A Crash Course

This notebook provides a hands-on introduction to using Deno in Jupyter. Deno is a modern, secure runtime for JavaScript and TypeScript that comes with built-in TypeScript support, security features, and a rich standard library.

14.1 1. Basic JavaScript/TypeScript Execution

Deno natively supports TypeScript without any configuration. You can write both JavaScript and TypeScript code directly.

// Basic TypeScript with type annotations
const greeting: string = "Hello from Deno!";
const version: string = Deno.version.deno;

console.log(greeting);
console.log(`Deno version: ${version}`);
Hello from Deno!
Deno version: 2.5.6
// Functions with type annotations
function add(a: number, b: number): number {
  return a + b;
}

function multiply(x: number, y: number): number {
  return x * y;
}

console.log(`5 + 3 = ${add(5, 3)}`);
console.log(`5 × 3 = ${multiply(5, 3)}`);
5 + 3 = 8
5 × 3 = 15

14.2 2. Importing Local Modules

Deno uses ES modules (ESM) and requires explicit file extensions in import statements.

// Import from local file (if calc.ts exists)
import { subtract } from "./calc.ts";
subtract(10, 3);
7

14.3 3. Importing from URLs

One of Deno’s unique features is the ability to import modules directly from URLs without a package manager.

// Import a simple utility from Deno's standard library
import { delay } from "https://deno.land/std@0.210.0/async/delay.ts";

console.log("Starting delay...");
await delay(1000); // Wait for 1 second
console.log("Done after 1 second!");
Starting delay...
Done after 1 second!

14.4 4. Working with Arrays and Iteration

Deno supports all modern JavaScript/TypeScript array methods.

const numbers: number[] = [1, 2, 3, 4, 5];

// Map
const squared: number[] = numbers.map(n => n ** 2);
console.log("Squared:", squared);

// Filter
const evenNumbers: number[] = numbers.filter(n => n % 2 === 0);
console.log("Even numbers:", evenNumbers);

// Reduce
const sum: number = numbers.reduce((acc, curr) => acc + curr, 0);
console.log("Sum:", sum);
Squared: [ 1, 4, 9, 16, 25 ]
Even numbers: [ 2, 4 ]
Sum: 15

14.5 5. Async/Await Operations

Deno is built around promises and async operations. Top-level await is supported.

// Async function example
async function fetchData(url: string): Promise<string> {
  await delay(500);
  return `Data from ${url}`;
}

// Top-level await works in Deno
const data: string = await fetchData("https://api.example.com");
console.log(data);
Data from https://api.example.com

14.6 6. HTTP Requests with fetch()

Deno has built-in support for the fetch() API, just like modern browsers.

// Fetch data from an API
const response: Response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
const jsonData: unknown = await response.json();

console.log("Fetched data:", jsonData);
Fetched data: { userId: 1, id: 1, title: "delectus aut autem", completed: false }

14.7 7. Working with JSON

Deno makes it easy to parse and stringify JSON data.

// Define an interface
interface Person {
  name: string;
  age: number;
  occupation: string;
}

// Create an object
const person: Person = {
  name: "Tom",
  age: 35,
  occupation: "Software Engineer"
};

// Convert to JSON
const jsonString: string = JSON.stringify(person, null, 2);
console.log("JSON string:");
console.log(jsonString);

// Parse JSON back to object
const parsedPerson: Person = JSON.parse(jsonString);
console.log("\nParsed object:", parsedPerson);
JSON string:
{
  "name": "Tom",
  "age": 35,
  "occupation": "Software Engineer"
}

Parsed object: { name: "Tom", age: 35, occupation: "Software Engineer" }

14.8 8. Using Deno’s Standard Library

Deno’s standard library provides many useful utilities.

// String manipulation from standard library
import { capitalize } from "https://deno.land/std@0.210.0/text/case.ts";

const text: string = "hello deno";
const capitalized: string = capitalize(text);
console.log(`Original: "${text}"`);
console.log(`Capitalized: "${capitalized}"`);
TypeError: Module not found "https://deno.land/std@0.210.0/text/case.ts".
Stack trace:
TypeError: Module not found "https://deno.land/std@0.210.0/text/case.ts".
    at async <anonymous>:2:24

14.9 9. File Operations

Deno provides APIs for file system operations.

// Write to a file
const textContent: string = "Hello from Deno in Jupyter!";
await Deno.writeTextFile("./test-output.txt", textContent);
console.log("File written successfully");

// Read from a file
const readContent: string = await Deno.readTextFile("./test-output.txt");
console.log("File content:", readContent);

// Clean up
// await Deno.remove("./test-output.txt");
// console.log("File removed");
File written successfully
File content: Hello from Deno in Jupyter!

14.10 10. Error Handling

Proper error handling is essential in production code.

// Try-catch for error handling
async function riskyOperation(shouldFail: boolean): Promise<string> {
  if (shouldFail) {
    throw new Error("Operation failed!");
  }
  return "Success!";
}

try {
  const result1: string = await riskyOperation(false);
  console.log("First call:", result1);
  
  const result2: string = await riskyOperation(true);
  console.log("Second call:", result2);
} catch (error: unknown) {
  if (error instanceof Error) {
    console.error("Caught error:", error.message);
  }
}
First call: Success!
Caught error: Operation failed!

14.11 11. Classes and OOP

TypeScript’s class syntax works seamlessly in Deno.

class Calculator {
  private history: string[] = [];

  add(a: number, b: number): number {
    const result: number = a + b;
    this.history.push(`${a} + ${b} = ${result}`);
    return result;
  }

  subtract(a: number, b: number): number {
    const result: number = a - b;
    this.history.push(`${a} - ${b} = ${result}`);
    return result;
  }

  getHistory(): string[] {
    return [...this.history];
  }
}

const calc = new Calculator();
console.log("10 + 5 =", calc.add(10, 5));
console.log("10 - 5 =", calc.subtract(10, 5));
console.log("History:", calc.getHistory());
10 + 5 = 15
10 - 5 = 5
History: [ "10 + 5 = 15", "10 - 5 = 5" ]

14.12 12. Summary

Key takeaways for using Deno in Jupyter:

  1. Native TypeScript Support: Write TypeScript directly without configuration
  2. Top-level Await: Use await at the top level without wrapping in async functions
  3. URL Imports: Import modules directly from URLs (Deno standard library, third-party)
  4. Built-in APIs: Access Web APIs like fetch(), file system APIs, and more
  5. Type Safety: Leverage TypeScript’s type system for better code quality
  6. Security: Deno is secure by default (though permissions work differently in Jupyter)

Happy coding with Deno!