> ## Documentation Index
> Fetch the complete documentation index at: https://learn.narau.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# TypeScript

> TypeScript — types, narrowing, generics, utility types, tsconfig, Zod, and more

[TypeScript](https://www.typescriptlang.org/) is a statically typed `superset` of JavaScript. Every valid `.js` file is already valid TypeScript, you layer types on top incrementally.

1. TypeScript compiles down to plain JavaScript, so the runtime (browser or Node.js) never sees a `.ts` file.

2. It adds a `compile` step between writing code and running it. That step is where all type errors are surfaced.

3. It does not change JavaScript's runtime behavior.

4. The types exist only at compile time, they are completely `erased` in the emitted JavaScript. They have zero `runtime` cost.

```ts twoslash TypeCheck.ts theme={null}
// @errors: 2345
function add(a: number, b: number) {
  return a + b;
}

// caught before running
add(1, "2");
```

### Checking JavaScript with tsc

You do not have to migrate to `.ts` files to get TypeScript's benefits.

```bash theme={null}
tsc --checkJs --noEmit --strict test.js
```

1. `--checkJs` enables type checking in `.js` files.
2. `--noEmit` only performs type-checking, does not output any compiled `.js` files.
3. `--strict` enables all strict type-checking options (recommended).
   * It is a shorthand that enables `strictNullChecks`, `noImplicitAny`, `strictFunctionTypes`, and several others at once.

> \[!WARNING] `watch` mode
> `watch` mode recompiles on file changes, but it only watches `.ts` files.

```bash "shorthand" theme={null}
tsc --watch
# or the shorthand
tsc -w

tsc types.ts --w --noEmit      
```

1. With a `tsconfig.json` present, just run `tsc -w` from the project root to watch all files.

### tsx

`tsx` is a fast TypeScript runner built on esbuild. It runs `.ts` and `.tsx` files directly without a separate compile step.

```bash "# run without installing globally" theme={null}
tsx watch script.ts

npx tsx script.ts # run without installing globally
```

1. Useful for scripts, CLI tools, and quick prototyping.

### tsconfig.json

The `tsconfig.json` file controls how TypeScript compiles your project.

1. You can create it manually or run `tsc --init` to generate a default one.

```json Expandable tsconfig.json theme={null}
{
  // Visit https://aka.ms/tsconfig to read more about this file
  "compilerOptions": {
    // File Layout
    // "rootDir": "./src",
    // "outDir": "./dist",
    // Environment Settings
    // See also https://aka.ms/tsconfig/module
    "module": "nodenext",
    "target": "esnext",
    "types": [],
    // For nodejs:
    // "lib": ["esnext"],
    // "types": ["node"],
    // and npm install -D @types/node

    // Other Outputs You may need these for libraries
    "sourceMap": true,
    "declaration": true,
    "declarationMap": true,

    // Stricter Typechecking Options
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,

    // Style Options
    // "noImplicitReturns": true,
    // "noImplicitOverride": true,
    // "noUnusedLocals": true,
    // "noUnusedParameters": true,
    // "noFallthroughCasesInSwitch": true,
    // "noPropertyAccessFromIndexSignature": true,

    // Recommended Options
    "strict": true,
    "jsx": "react-jsx",
    "verbatimModuleSyntax": true,
    "isolatedModules": true,
    "noUncheckedSideEffectImports": true,
    "moduleDetection": "force",
    "skipLibCheck": true,
  }
}
```

2. You can learn about all the options in the [TypeScript Handbook](https://www.typescriptlang.org/tsconfig), or check this cheatsheet on [Total Typescript](https://www.totaltypescript.com/tsconfig-cheat-sheet).

### Type Annotations

You annotate variables, parameters, and return types with `: type`.

```ts twoslash theme={null}
#types.ts
let name: string = "Alice";
let age: number = 30;
let active: boolean = true;

function greet(user: string): string {
  return `Hello, ${user}`;
}
```

1. TypeScript can also infer types, you don't always have to annotate.

```ts twoslash theme={null}
let name = "Alice";
//   ^?
```

### Literal Types

Instead of a broad type like `string`, a literal type restricts a value to one specific value.

```ts twoslash theme={null}
#literal-types.ts
let direction: "left" | "right" = "left";

// @errors: 2322
direction = "up";
```

1. These are especially useful in function parameters to restrict allowed values.

```ts twoslash theme={null}
#direction-param.ts
function move(dir: "up" | "down" | "left" | "right") {
  console.log(dir);
}

move("up");
```

### Strict Null Checks

Without `strictNullChecks`, `null` and `undefined` are assignable to any type, a common source of runtime bugs.

1. With it enabled, you must explicitly handle `null` and `undefined`.

```ts twoslash theme={null}
// @strict: true
// @errors: 2322
let name: string = null;
```

2. To allow `null`, use a union type:

```ts twoslash theme={null}
let name: string | null = null;
```

### Union Types

A `union` type means a value can be one of several types.

```ts twoslash theme={null}
#union.ts
function formatId(id: number | string) {
  return `ID: ${id}`;
}
```

### Type Narrowing and Type Guards

TypeScript tracks types through `conditional` branches, this is called `narrowing`.

1. A `type guard` is any expression that narrows the type in a scope.

```ts twoslash theme={null}
#type-guards.ts
function print(val: string | number) {
  if (typeof val === "string") {
    console.log(val.toUpperCase());
  } else {
    console.log(val.toFixed(2));
  }
}
```

### Type Aliases and Interfaces

Both let you name a type, but they have different strengths.

```ts twoslash theme={null}
#aliases-interfaces.ts
type Point = {
  x: number;
  y: number;
};

interface User {
  id: number | string;
  name: string;
}
```

> \[!WARNING] Usage
> Use a type alias for primitives and interface for object shapes, but this is a convention, not a rule.

1. Type aliases can represent any type, including `unions` and `primitives`, while interfaces are primarily for `object` shapes.

```ts del="@error: 1005 | 2693" theme={null}
#aliases.ts
type ID = string;
type IsAdmin = boolean;

type Status = "success" | "error" | "loading";

// @error: 1005 | 2693
interface ID = string;
interface Status = "success" | "error";
```

2. Interfaces can `extend` other interfaces, while type aliases use `intersections`.

```ts twoslash theme={null}
#extend.ts
interface User {
    name: string
}

interface Employee extends User {
    role: string
}

let u : Employee = {name: "Mahraib Fatima", role: "AI/ML Engineer"}
```

3. Declaration merging $—$ interfaces with the same name are merged automatically.

```ts twoslash theme={null}
#declaration-merging.ts
interface Website {
  title: string;
}

interface Website {
  theme: "dark" | "light";
}

// @error: Types cannot be reopened this way
let a : Website = {title: "Jujutsu Kaisen", theme: "dark"}
```

### Promises

Promises in TypeScript are generic, you declare what they resolve to.

```ts twoslash theme={null}
#promises.ts
async function getName(): Promise<string>{
  return "Mahraib Fatima";
}
```

> \[!WARNING] Return Types
> TypeScript will infer the return type in most cases, but being explicit is useful.

### Generics

Generics let you write reusable code that works with any type while preserving type safety.

```diff lang="ts" twoslash theme={null}
#generics.ts
type User<T> = {
    id: T,
    username: string
}

// @errors: 2314
+let user: User = {id: 1, username: 'Novid Azhr'}
-let mahraib: User<string> = {id: "1", username: 'Mahraib Fatima'}
```

1. You can constrain generics with `extends`.

```ts twoslash wrap ins="// 5" ins="// 3" theme={null}
#constrained-generics.ts
function getLength<T extends { length: number }>(val: T): number {
  return val.length;
}

getLength("hello"); // 5
getLength([1, 2, 3]); // 3
```

### Utility Types

TypeScript ships built-in generic types for common transformations.

1. `Readonly<T>` makes all properties immutable.

```ts twoslash theme={null}
#readonly.ts
interface Config {
  host: string;
  port: number;
}

const cfg: Readonly<Config> = { host: "localhost", port: 3000 };
// @errors: 2540
cfg.port = 8080;
```

```ts twoslash  theme={null}
#readonly-interface.ts
interface User {
    readonly id: number,
    username: string
}

let user: User = {id: 1, username: "Adam Rofayel"};
// @errors: 2540
user.id = 2
```

2. `Partial<T>` makes all properties optional, useful for update$/$patch operations.

```ts ins="// other fields omitted" twoslash theme={null}
interface User {
  name: string;
  email: string;
  age: number;
}

function updateUser(id: number, patch: Partial<User>) {}

updateUser(1, { name: "Bob" }); // other fields omitted
```

3. `Pick<T, K>` constructs a type with only the specified keys.

```ts twoslash theme={null}
interface User {
  id: number;
  name: string;
  email: string;
  password: string;
}

type PublicUser = Pick<User, "id" | "name" | "email">;
//   ^?
```

4. `Omit<T, K>` is the opposite of `Pick`, builds a type without the specified keys.

```ts twoslash theme={null}
interface User {
  id: number;
  name: string;
  email: string;
  password: string;
}

type SafeUser = Omit<User, "password">;
//   ^?
```

### any & unknown

`any` opts a value completely out of the type system. Use it as a last resort.

```ts twoslash theme={null}
let x: any = "hello";
x = 42;

// @error: no error, dangerous at runtime
x.foo.bar();
```

1. If you find yourself reaching for `any`, consider `unknown` first.

   2. Both can hold any value, but `unknown` is safer, you must narrow it before using it.

```ts twoslash ins="// Error — must narrow first" theme={null}
// @errors: 18046
let a: any = "hello";

// @log: no error, but runtime error if a is not a string
a.toUpperCase();

let b: unknown = "hello";

// Error — must narrow first
b.toUpperCase(); 

if (typeof b === "string") {
  b.toUpperCase();
}
```

### Index Access Types

Extract the type of a property using bracket notation on a type.

```ts twoslash theme={null}
interface User {
  id: number;
  name: string;
  address: {
    city: string;
    zip: string;
  };
}

type UserName = User["name"];
//   ^?

type City = User["address"]["city"];
//   ^?

type Address = User["address"];
//   ^?
```

### Type Assertions

Type assertions tell the compiler to treat a value as a specific type, using `as`.

```ts twoslash wrap theme={null}
// @lib: dom
let input = document.getElementById("name") as HTMLInputElement;

// @log: TypeScript now knows input is an HTMLInputElement
input.value = "Alice";
```

> \[!WARNING] Unsafe Assertions
> `as` does not perform runtime checks. If you're wrong, you get a runtime error, not a compile error. Use type guards when possible.

### DefinitelyTyped

Many npm packages are written in JavaScript and don't include types. The community publishes type definitions under the `@types` scope on npm.

```bash theme={null}
npm install -D @types/node
```

1. These come from the [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) repository.

## Zod

[Zod](https://zod.dev/) is a schema declaration and validation library. It bridges the gap between TypeScript's static types (compile-time) and runtime data validation.

1. TypeScript types are erased at runtime, they can't validate an API response.
2. Zod schemas validate at runtime and infer the TypeScript type automatically.

```ts twoslash theme={null}
/// <reference types="zod" />
// ---cut---
import { z } from "zod";

const UserSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string().email(),
});

// @log: To get the TypeScript type from a Zod schema
type User = z.infer<typeof UserSchema>;
//   ^?

const result = UserSchema.safeParse({
  id: 1,
  name: "Alice",
  email: "alice@example.com",
});

if (!result.success) {
  throw new Error("Invalid");
}

result.data.name;
//          ^?
```
