From 6e82439632d1f67a884d6a39296898660e16f818 Mon Sep 17 00:00:00 2001 From: Mostafa Date: Wed, 15 Jul 2026 08:47:14 +0300 Subject: [PATCH 1/4] fix-update package.json to run project --- package-lock.json | 1301 +++++++++++++++++++-------------------------- package.json | 2 +- 2 files changed, 558 insertions(+), 745 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1e12570..f6b10d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { "name": "try-typescript", - "version": "0.0.0", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "try-typescript", - "version": "0.0.0", + "version": "1.0.1", "license": "ISC", "dependencies": { "@monaco-editor/react": "^4.7.0", - "@tailwindcss/vite": "^4.0.0", + "@tailwindcss/vite": "^4.3.0", "canvas-confetti": "^1.9.3", "lucide-react": "^0.577.0", "react": "^19.2.4", @@ -31,24 +31,24 @@ } }, "node_modules/@cloudflare/kv-asset-handler": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.2.tgz", - "integrity": "sha512-SIOD2DxrRRwQ+jgzlXCqoEFiKOFqaPjhnNTGKXSRLvp1HiOvapLaFG2kEr9dYQTYe8rKrd9uvDUzmAITeNyaHQ==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.5.0.tgz", + "integrity": "sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==", "dev": true, "license": "MIT OR Apache-2.0", "engines": { - "node": ">=18.0.0" + "node": ">=22.0.0" } }, "node_modules/@cloudflare/unenv-preset": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.15.0.tgz", - "integrity": "sha512-EGYmJaGZKWl+X8tXxcnx4v2bOZSjQeNI5dWFeXivgX9+YCT69AkzHHwlNbVpqtEUTbew8eQurpyOpeN8fg00nw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.16.1.tgz", + "integrity": "sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==", "dev": true, "license": "MIT OR Apache-2.0", "peerDependencies": { "unenv": "2.0.0-rc.24", - "workerd": "1.20260301.1 || ~1.20260302.1 || ~1.20260303.1 || ~1.20260304.1 || >1.20260305.0 <2.0.0-0" + "workerd": ">1.20260305.0 <2.0.0-0" }, "peerDependenciesMeta": { "workerd": { @@ -57,9 +57,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20260312.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260312.1.tgz", - "integrity": "sha512-HUAtDWaqUduS6yasV6+NgsK7qBpP1qGU49ow/Wb117IHjYp+PZPUGReDYocpB4GOMRoQlvdd4L487iFxzdARpw==", + "version": "1.20260708.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260708.1.tgz", + "integrity": "sha512-HXFCvhS1wpg3uXO0CLUwmwC41i2loM5FSK69EUchOBpmYBAXxT1oHLm6EOA5lqhTk5Mu9kjRiQYxa1GwKPwfJg==", "cpu": [ "x64" ], @@ -74,9 +74,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20260312.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260312.1.tgz", - "integrity": "sha512-DOn7TPTHSxJYfi4m4NYga/j32wOTqvJf/pY4Txz5SDKWIZHSTXFyGz2K4B+thoPWLop/KZxGoyTv7db0mk/qyw==", + "version": "1.20260708.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260708.1.tgz", + "integrity": "sha512-JVlJaKDoRTVKSroHIlf8g3UCPjKj4iDbMZE2CNYht5qQ+2rL0FAUiVlV82G3BqKnnw9kHYnnsMzC08b9zVtdzA==", "cpu": [ "arm64" ], @@ -91,9 +91,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20260312.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260312.1.tgz", - "integrity": "sha512-TdkIh3WzPXYHuvz7phAtFEEvAxvFd30tHrm4gsgpw0R0F5b8PtoM3hfL2uY7EcBBWVYUBtkY2ahDYFfufnXw/g==", + "version": "1.20260708.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260708.1.tgz", + "integrity": "sha512-3daE60YdD7YX0Jtuzc9DE/r/qMkmx8ZvHTkF8Mzmp3F5tbzlV0DAzmu5PFUPF2WuvtKbAhZKbvC2cHmWpQYxnA==", "cpu": [ "x64" ], @@ -108,9 +108,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20260312.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260312.1.tgz", - "integrity": "sha512-kNauZhL569Iy94t844OMwa1zP6zKFiL3xiJ4tGLS+TFTEfZ3pZsRH6lWWOtkXkjTyCmBEOog0HSEKjIV4oAffw==", + "version": "1.20260708.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260708.1.tgz", + "integrity": "sha512-VLdNYOx5Hj+9C6isy0ACWZsbMtSxex2DIJWEe7cZxUdlphZ58ZT8zxNXK8yunFiowd34hn3VwGMopdvdj8lvmA==", "cpu": [ "arm64" ], @@ -125,9 +125,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20260312.1", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260312.1.tgz", - "integrity": "sha512-5dBrlSK+nMsZy5bYQpj8t9iiQNvCRlkm9GGvswJa9vVU/1BNO4BhJMlqOLWT24EmFyApZ+kaBiPJMV8847NDTg==", + "version": "1.20260708.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260708.1.tgz", + "integrity": "sha512-bC/aSAwLy16Vjo24i9XU3aWH+eRgz7NeR5xPKavGbembO18ZywYTQbXh14eXtY6fAqN3RzRG8psijTdhX4xydA==", "cpu": [ "x64" ], @@ -166,20 +166,20 @@ } }, "node_modules/@emnapi/core": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz", - "integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", + "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", "license": "MIT", "optional": true, "dependencies": { - "@emnapi/wasi-threads": "1.2.0", + "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz", - "integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", + "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", "license": "MIT", "optional": true, "dependencies": { @@ -187,9 +187,9 @@ } }, "node_modules/@emnapi/wasi-threads": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz", - "integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", "license": "MIT", "optional": true, "dependencies": { @@ -197,13 +197,12 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -214,13 +213,12 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -231,13 +229,12 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -248,13 +245,12 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -265,13 +261,12 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -282,13 +277,12 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -299,13 +293,12 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -316,13 +309,12 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -333,13 +325,12 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -350,13 +341,12 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -367,13 +357,12 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -384,13 +373,12 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -401,13 +389,12 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -418,13 +405,12 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -435,13 +421,12 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -452,13 +437,12 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -469,13 +453,12 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -486,13 +469,12 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -503,13 +485,12 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -520,13 +501,12 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -537,13 +517,12 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -554,13 +533,12 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -571,13 +549,12 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -588,13 +565,12 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -605,13 +581,12 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -622,13 +597,12 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -736,6 +710,9 @@ "arm" ], "dev": true, + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -753,6 +730,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -770,6 +750,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -787,6 +770,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -804,6 +790,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -821,6 +810,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -838,6 +830,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -855,6 +850,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "LGPL-3.0-or-later", "optional": true, "os": [ @@ -872,6 +870,9 @@ "arm" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -895,6 +896,9 @@ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -918,6 +922,9 @@ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -941,6 +948,9 @@ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -964,6 +974,9 @@ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -987,6 +1000,9 @@ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1010,6 +1026,9 @@ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1033,6 +1052,9 @@ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "Apache-2.0", "optional": true, "os": [ @@ -1197,36 +1219,27 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz", - "integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1", - "@tybys/wasm-util": "^0.10.1" + "@tybys/wasm-util": "^0.10.3" }, "funding": { "type": "github", "url": "https://github.com/sponsors/Brooooooklyn" - } - }, - "node_modules/@oxc-project/runtime": { - "version": "0.115.0", - "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.115.0.tgz", - "integrity": "sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" } }, "node_modules/@oxc-project/types": { - "version": "0.115.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.115.0.tgz", - "integrity": "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==", - "dev": true, + "version": "0.139.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz", + "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/Boshen" @@ -1908,13 +1921,12 @@ "license": "MIT" }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.9.tgz", - "integrity": "sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz", + "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1925,13 +1937,12 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.9.tgz", - "integrity": "sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz", + "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1942,13 +1953,12 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.9.tgz", - "integrity": "sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz", + "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1959,13 +1969,12 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.9.tgz", - "integrity": "sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz", + "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1976,13 +1985,12 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.9.tgz", - "integrity": "sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz", + "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==", "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -1993,13 +2001,15 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.9.tgz", - "integrity": "sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz", + "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==", "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2010,13 +2020,15 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.9.tgz", - "integrity": "sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz", + "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==", "cpu": [ "arm64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2027,13 +2039,15 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.9.tgz", - "integrity": "sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz", + "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==", "cpu": [ "ppc64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2044,13 +2058,15 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.9.tgz", - "integrity": "sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz", + "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==", "cpu": [ "s390x" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2061,13 +2077,15 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.9.tgz", - "integrity": "sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz", + "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==", "cpu": [ "x64" ], - "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2078,13 +2096,15 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.9.tgz", - "integrity": "sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz", + "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==", "cpu": [ "x64" ], - "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2095,13 +2115,12 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.9.tgz", - "integrity": "sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz", + "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2112,30 +2131,30 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.9.tgz", - "integrity": "sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz", + "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==", "cpu": [ "wasm32" ], - "dev": true, "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.1" + "@emnapi/core": "1.11.1", + "@emnapi/runtime": "1.11.1", + "@napi-rs/wasm-runtime": "^1.1.6" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.9.tgz", - "integrity": "sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz", + "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==", "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2146,13 +2165,12 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.9.tgz", - "integrity": "sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz", + "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2183,54 +2201,54 @@ } }, "node_modules/@speed-highlight/core": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.14.tgz", - "integrity": "sha512-G4ewlBNhUtlLvrJTb88d2mdy2KRijzs4UhnlrOSRT4bmjh/IqNElZa3zkrZ+TC47TwtlDWzVLFADljF1Ijp5hA==", + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.17.tgz", + "integrity": "sha512-Z92FwKpCtfaW1V0jTU/fh3QzYEZN8wDwrzRIBoADCJfn4mJCNcJN/XegifX7BDrQ8/h9Xh/JnbyMchL0FqXrkg==", "dev": true, "license": "CC0-1.0" }, "node_modules/@tailwindcss/node": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz", - "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.2.tgz", + "integrity": "sha512-yWP/sqEcBLaD8JuA6zNwxoYKr75qxTioYwlRwekj5Jr/I5GXnoJfjetH/psLUIv74cYTH2lBUEzBkinthoYcBg==", "license": "MIT", "dependencies": { "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.19.0", - "jiti": "^2.6.1", - "lightningcss": "1.31.1", + "enhanced-resolve": "5.21.6", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", - "tailwindcss": "4.2.1" + "tailwindcss": "4.3.2" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz", - "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.2.tgz", + "integrity": "sha512-z8ZgnzX8gdNoWLBLqBPoh/sjnxkwvf9ZuWjnO0l0yIzbLa5/9S+eC5QxGZKRobVHIC3/1BoMWjHblqWjcgFgag==", "license": "MIT", "engines": { "node": ">= 20" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.2.1", - "@tailwindcss/oxide-darwin-arm64": "4.2.1", - "@tailwindcss/oxide-darwin-x64": "4.2.1", - "@tailwindcss/oxide-freebsd-x64": "4.2.1", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1", - "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1", - "@tailwindcss/oxide-linux-arm64-musl": "4.2.1", - "@tailwindcss/oxide-linux-x64-gnu": "4.2.1", - "@tailwindcss/oxide-linux-x64-musl": "4.2.1", - "@tailwindcss/oxide-wasm32-wasi": "4.2.1", - "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1", - "@tailwindcss/oxide-win32-x64-msvc": "4.2.1" + "@tailwindcss/oxide-android-arm64": "4.3.2", + "@tailwindcss/oxide-darwin-arm64": "4.3.2", + "@tailwindcss/oxide-darwin-x64": "4.3.2", + "@tailwindcss/oxide-freebsd-x64": "4.3.2", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.2", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.2", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.2", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.2", + "@tailwindcss/oxide-linux-x64-musl": "4.3.2", + "@tailwindcss/oxide-wasm32-wasi": "4.3.2", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.2", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.2" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz", - "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.2.tgz", + "integrity": "sha512-WHxqIuHpvZ5VtdX6GTl1Ik/Vp2YuN42Et+0CdeaVd/frQ9jAvGmvR8vLT+jk3e8/Q3x8kECB9+R17pgpp2BulA==", "cpu": [ "arm64" ], @@ -2244,9 +2262,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz", - "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.2.tgz", + "integrity": "sha512-GZypeUY/IDJW3877KeM+O67vbXr3MBnbtEL4aYhNErv/JWZhye2vGSWWG9tB6iiqR2MqRNkY8IOUy4NdSZV26w==", "cpu": [ "arm64" ], @@ -2260,9 +2278,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz", - "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.2.tgz", + "integrity": "sha512-UIIzmefR6KO1sDU7MzRqAxC8iBpft/VhkGjTjnhoS6k7Z3rQ9wEgA1ODSiyH/tcSYssulNm4Ci3hOeK1jH7ccQ==", "cpu": [ "x64" ], @@ -2276,9 +2294,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz", - "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.2.tgz", + "integrity": "sha512-GN+uAmcI6DNspnCDwtOAZrTz6oukJnp337qZvxqCGLd3BHBzJpO0ZbTLRvJNdztOeAmTzewewGIMPb0tk2R4WA==", "cpu": [ "x64" ], @@ -2292,9 +2310,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz", - "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.2.tgz", + "integrity": "sha512-4ABn7qSbdHRwTiDiuWNegCyb5+2FJ4vKIKc3DmKrvAFw7MU1Lm11dIkTPwUaFdTzc7IsOpDbqBrlh0x6y36U/w==", "cpu": [ "arm" ], @@ -2308,12 +2326,15 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz", - "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.2.tgz", + "integrity": "sha512-wDgEIGwoM8w8pufh9LVt1PahDgNdKXrLC2qfAnV3vAmococ9RWbxeAw4pxPttd/TsJfwjyLf90Dg1y9y8I6Emw==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2324,12 +2345,15 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz", - "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.2.tgz", + "integrity": "sha512-J5Nuk0uZQIiMTJj3LEx4sAA9tMFUoXQZFv1J6An+QGYe53HKRJuFDi0rpq/tuouCZeAbOBY3kQ6g8qeD4TUjtA==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2340,12 +2364,15 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz", - "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.2.tgz", + "integrity": "sha512-kqCZpSKOBEJO4mz7OqWoofBZeXTAwaVGPj0ErAj7CojmhKpWVWVOnrt9dE8odoIraZq4oj3ausM37kXi+Tow8w==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2356,12 +2383,15 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz", - "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.2.tgz", + "integrity": "sha512-cixpqbh2toJDmkuCRI68nXA8ZxNmdK9Y+9v5h3MC3ZQKy/0BO8AWzlkWyRM7JAFSGBlfig4YVTPsK6MVgqz1uw==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2372,9 +2402,9 @@ } }, "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz", - "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.2.tgz", + "integrity": "sha512-4ec2Z/LOmRsAgU23CS4xeJfcJlmRg94A/XrbGRCF1gyU/zdDfRLYDVsS+ynSZCmGNxQ1jQriQOKMQeQxBA3Isw==", "bundleDependencies": [ "@napi-rs/wasm-runtime", "@emnapi/core", @@ -2389,11 +2419,11 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "^1.8.1", - "@emnapi/runtime": "^1.8.1", - "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.1.1", - "@tybys/wasm-util": "^0.10.1", + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", "tslib": "^2.8.1" }, "engines": { @@ -2401,9 +2431,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz", - "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.2.tgz", + "integrity": "sha512-Zyr/M0+XcYZu3bZrUytc7TXvrk0ftWfl8gN2MwekNDzhqhKRUucMPSeOzM0o0wH5AWOU49BsKRrfKxI2atCPMQ==", "cpu": [ "arm64" ], @@ -2417,9 +2447,9 @@ } }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz", - "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.2.tgz", + "integrity": "sha512-QI9BO7KlNZsp2GuO0jwAAj5jCDABOKXRkCk2XuKTSaNEFSdfzqswYVTtCHBNKHLsqyjFyFkqlDiwkNbTYSssMQ==", "cpu": [ "x64" ], @@ -2433,23 +2463,23 @@ } }, "node_modules/@tailwindcss/vite": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.1.tgz", - "integrity": "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.3.2.tgz", + "integrity": "sha512-eHpMeX4JXfVNJDEcsouTeCBubJBTcTLigeaw/NTUW6PB5ATKKXdyonnXgTBX2VuRbjz1hjfz6C5XAhr52ImQXA==", "license": "MIT", "dependencies": { - "@tailwindcss/node": "4.2.1", - "@tailwindcss/oxide": "4.2.1", - "tailwindcss": "4.2.1" + "@tailwindcss/node": "4.3.2", + "@tailwindcss/oxide": "4.3.2", + "tailwindcss": "4.3.2" }, "peerDependencies": { - "vite": "^5.2.0 || ^6 || ^7" + "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz", + "integrity": "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==", "license": "MIT", "optional": true, "dependencies": { @@ -2467,7 +2497,7 @@ "version": "24.12.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.0.tgz", "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~7.16.0" @@ -2493,6 +2523,14 @@ "@types/react": "^19.2.0" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/@vitejs/plugin-react": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", @@ -2566,14 +2604,24 @@ "node": ">=8" } }, + "node_modules/dompurify": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", + "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "peer": true, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/enhanced-resolve": { - "version": "5.20.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", - "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", - "tapable": "^2.3.0" + "tapable": "^2.3.3" }, "engines": { "node": ">=10.13.0" @@ -2590,10 +2638,10 @@ } }, "node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", - "dev": true, + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "devOptional": true, "hasInstallScript": true, "license": "MIT", "bin": { @@ -2603,39 +2651,38 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -2653,7 +2700,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -2671,9 +2717,9 @@ "license": "ISC" }, "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -2690,9 +2736,9 @@ } }, "node_modules/lightningcss": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz", - "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", "license": "MPL-2.0", "dependencies": { "detect-libc": "^2.0.3" @@ -2705,23 +2751,23 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-android-arm64": "1.31.1", - "lightningcss-darwin-arm64": "1.31.1", - "lightningcss-darwin-x64": "1.31.1", - "lightningcss-freebsd-x64": "1.31.1", - "lightningcss-linux-arm-gnueabihf": "1.31.1", - "lightningcss-linux-arm64-gnu": "1.31.1", - "lightningcss-linux-arm64-musl": "1.31.1", - "lightningcss-linux-x64-gnu": "1.31.1", - "lightningcss-linux-x64-musl": "1.31.1", - "lightningcss-win32-arm64-msvc": "1.31.1", - "lightningcss-win32-x64-msvc": "1.31.1" + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" } }, "node_modules/lightningcss-android-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz", - "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", "cpu": [ "arm64" ], @@ -2739,9 +2785,9 @@ } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz", - "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", "cpu": [ "arm64" ], @@ -2759,9 +2805,9 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz", - "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", "cpu": [ "x64" ], @@ -2779,9 +2825,9 @@ } }, "node_modules/lightningcss-freebsd-x64": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz", - "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", "cpu": [ "x64" ], @@ -2799,9 +2845,9 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz", - "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", "cpu": [ "arm" ], @@ -2819,12 +2865,15 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz", - "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2839,12 +2888,15 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz", - "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2859,12 +2911,15 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz", - "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2879,12 +2934,15 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz", - "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MPL-2.0", "optional": true, "os": [ @@ -2899,9 +2957,9 @@ } }, "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz", - "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", "cpu": [ "arm64" ], @@ -2919,9 +2977,9 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.31.1", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz", - "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==", + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", "cpu": [ "x64" ], @@ -2956,32 +3014,55 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/marked": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", + "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", + "license": "MIT", + "peer": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/miniflare": { - "version": "4.20260312.0", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260312.0.tgz", - "integrity": "sha512-pieP2rfXynPT6VRINYaiHe/tfMJ4c5OIhqRlIdLF6iZ9g5xgpEmvimvIgMpgAdDJuFlrLcwDUi8MfAo2R6dt/w==", + "version": "4.20260708.1", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260708.1.tgz", + "integrity": "sha512-c94O9zRDISdqO18EHt6l0iF/fWgWt8p18PJvRsA/L/NJZ9Cfke3s/F5Blg1XXF7WDutVRzWVWy8Vy4LaT5ifsA==", "dev": true, "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "0.8.1", - "sharp": "^0.34.5", - "undici": "7.18.2", - "workerd": "1.20260312.1", - "ws": "8.18.0", + "sharp": "0.34.5", + "undici": "7.28.0", + "workerd": "1.20260708.1", + "ws": "8.21.0", "youch": "4.1.0-beta.10" }, "bin": { "miniflare": "bootstrap.js" }, "engines": { - "node": ">=18.0.0" + "node": ">=22.0.0" + } + }, + "node_modules/monaco-editor": { + "version": "0.55.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", + "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", + "license": "MIT", + "peer": true, + "dependencies": { + "dompurify": "3.2.7", + "marked": "14.0.0" } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "funding": [ { "type": "github", @@ -3099,14 +3180,12 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "license": "MIT", "engines": { "node": ">=12" @@ -3116,10 +3195,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", - "dev": true, + "version": "8.5.19", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.19.tgz", + "integrity": "sha512-Mz8SaolMd8nB+G13WkORcxQKHZ/NE4xXevtkJHVuG+guo9/wYKlIMTKAqGdEmYOXR2ijPjTYNHssizdaVSUNdQ==", "funding": [ { "type": "opencollective", @@ -3136,7 +3214,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -3166,14 +3244,13 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.9.tgz", - "integrity": "sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==", - "dev": true, + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz", + "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==", "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.115.0", - "@rolldown/pluginutils": "1.0.0-rc.9" + "@oxc-project/types": "=0.139.0", + "@rolldown/pluginutils": "^1.0.0" }, "bin": { "rolldown": "bin/cli.mjs" @@ -3182,28 +3259,27 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.9", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.9", - "@rolldown/binding-darwin-x64": "1.0.0-rc.9", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.9", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.9", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.9", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.9", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.9", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.9", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.9", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.9", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.9" + "@rolldown/binding-android-arm64": "1.1.5", + "@rolldown/binding-darwin-arm64": "1.1.5", + "@rolldown/binding-darwin-x64": "1.1.5", + "@rolldown/binding-freebsd-x64": "1.1.5", + "@rolldown/binding-linux-arm-gnueabihf": "1.1.5", + "@rolldown/binding-linux-arm64-gnu": "1.1.5", + "@rolldown/binding-linux-arm64-musl": "1.1.5", + "@rolldown/binding-linux-ppc64-gnu": "1.1.5", + "@rolldown/binding-linux-s390x-gnu": "1.1.5", + "@rolldown/binding-linux-x64-gnu": "1.1.5", + "@rolldown/binding-linux-x64-musl": "1.1.5", + "@rolldown/binding-openharmony-arm64": "1.1.5", + "@rolldown/binding-wasm32-wasi": "1.1.5", + "@rolldown/binding-win32-arm64-msvc": "1.1.5", + "@rolldown/binding-win32-x64-msvc": "1.1.5" } }, "node_modules/rolldown/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.9", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.9.tgz", - "integrity": "sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==", - "dev": true, + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", "license": "MIT" }, "node_modules/scheduler": { @@ -3213,9 +3289,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, "license": "ISC", "bin": { @@ -3299,15 +3375,15 @@ } }, "node_modules/tailwindcss": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz", - "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.2.tgz", + "integrity": "sha512-WtctNNSH8A9jlMIqxzuYumOHU5uGZyRv0Q5svQl+oEPy5w84YpBxdb7MdqyiSPQge5jTJ6zFQLq0PFygdccSBA==", "license": "MIT" }, "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", "license": "MIT", "engines": { "node": ">=6" @@ -3318,14 +3394,13 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -3366,9 +3441,9 @@ } }, "node_modules/undici": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.18.2.tgz", - "integrity": "sha512-y+8YjDFzWdQlSE9N5nzKMT3g4a5UBX1HKowfdXh0uvAnTaqqwqB92Jt4UXBAeKekDs5IaDKyJFR4X1gYVCgXcw==", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", + "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", "dev": true, "license": "MIT", "engines": { @@ -3379,7 +3454,7 @@ "version": "7.16.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/unenv": { @@ -3393,18 +3468,16 @@ } }, "node_modules/vite": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.0.tgz", - "integrity": "sha512-fPGaRNj9Zytaf8LEiBhY7Z6ijnFKdzU/+mL8EFBaKr7Vw1/FWcTBAMW0wLPJAGMPX38ZPVCVgLceWiEqeoqL2Q==", - "dev": true, + "version": "8.1.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.4.tgz", + "integrity": "sha512-bTT9PsdWO+MQMNG9ZXIP/qM9wGh37DFxTV/sPq9cFpHr3w4jkgef032PkAL9jAqhk3Nz8NQw3O8n6/xFkqO4QQ==", "license": "MIT", "dependencies": { - "@oxc-project/runtime": "0.115.0", "lightningcss": "^1.32.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.9", - "tinyglobby": "^0.2.15" + "picomatch": "^4.0.5", + "postcss": "^8.5.16", + "rolldown": "~1.1.4", + "tinyglobby": "^0.2.17" }, "bin": { "vite": "bin/vite.js" @@ -3420,8 +3493,8 @@ }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.0.0-alpha.31", - "esbuild": "^0.27.0", + "@vitejs/devtools": "^0.3.0", + "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", @@ -3471,271 +3544,10 @@ } } }, - "node_modules/vite/node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/vite/node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/vite/node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/workerd": { - "version": "1.20260312.1", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260312.1.tgz", - "integrity": "sha512-nNpPkw9jaqo79B+iBCOiksx+N62xC+ETIfyzofUEdY3cSOHJg6oNnVSHm7vHevzVblfV76c8Gr0cXHEapYMBEg==", + "version": "1.20260708.1", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260708.1.tgz", + "integrity": "sha512-WAK+Kt/VVCSldH2qSr8lx46XCJ4Q+bdlHNaFqUtOHthBEIB8C1N8HVW+VOLrxDoTCk0NGNv0zajnBeQK4JOB9w==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -3746,41 +3558,42 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20260312.1", - "@cloudflare/workerd-darwin-arm64": "1.20260312.1", - "@cloudflare/workerd-linux-64": "1.20260312.1", - "@cloudflare/workerd-linux-arm64": "1.20260312.1", - "@cloudflare/workerd-windows-64": "1.20260312.1" + "@cloudflare/workerd-darwin-64": "1.20260708.1", + "@cloudflare/workerd-darwin-arm64": "1.20260708.1", + "@cloudflare/workerd-linux-64": "1.20260708.1", + "@cloudflare/workerd-linux-arm64": "1.20260708.1", + "@cloudflare/workerd-windows-64": "1.20260708.1" } }, "node_modules/wrangler": { - "version": "4.73.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.73.0.tgz", - "integrity": "sha512-VJXsqKDFCp6OtFEHXITSOR5kh95JOknwPY8m7RyQuWJQguSybJy43m4vhoCSt42prutTef7eeuw7L4V4xiynGw==", + "version": "4.110.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.110.0.tgz", + "integrity": "sha512-xZeXKYi7hxQRF5anL+v77RkufJNpF9f3Eqeyqq2QBsETpLZgh0Agj0jJ6JPtkbgn6ukZdh8OK5egsGPWIditgg==", "dev": true, "license": "MIT OR Apache-2.0", "dependencies": { - "@cloudflare/kv-asset-handler": "0.4.2", - "@cloudflare/unenv-preset": "2.15.0", + "@cloudflare/kv-asset-handler": "0.5.0", + "@cloudflare/unenv-preset": "2.16.1", "blake3-wasm": "2.1.5", - "esbuild": "0.27.3", - "miniflare": "4.20260312.0", + "esbuild": "0.28.1", + "miniflare": "4.20260708.1", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", - "workerd": "1.20260312.1" + "workerd": "1.20260708.1" }, "bin": { + "cf-wrangler": "bin/cf-wrangler.js", "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" }, "engines": { - "node": ">=20.0.0" + "node": ">=22.0.0" }, "optionalDependencies": { - "fsevents": "~2.3.2" + "fsevents": "2.3.3" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20260312.1" + "@cloudflare/workers-types": "^5.20260708.1" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { @@ -3789,9 +3602,9 @@ } }, "node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index c6eb35e..e2278d1 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ }, "dependencies": { "@monaco-editor/react": "^4.7.0", - "@tailwindcss/vite": "^4.0.0", + "@tailwindcss/vite": "^4.3.0", "canvas-confetti": "^1.9.3", "lucide-react": "^0.577.0", "react": "^19.2.4", From 9f178f75c823f1179edace5d609dfecc6860fe38 Mon Sep 17 00:00:00 2001 From: Mostafa Date: Fri, 17 Jul 2026 08:51:47 +0300 Subject: [PATCH 2/4] Fix-name variabe is declared as global scope --- src/data/lessons/lessons-en.ts | 1746 ++++++++++++++++--------------- src/data/lessons/lessons.ts | 1774 ++++++++++++++++---------------- 2 files changed, 1787 insertions(+), 1733 deletions(-) diff --git a/src/data/lessons/lessons-en.ts b/src/data/lessons/lessons-en.ts index 0e6b7e5..a2ceef7 100644 --- a/src/data/lessons/lessons-en.ts +++ b/src/data/lessons/lessons-en.ts @@ -1,17 +1,17 @@ -import type { Lesson } from "./types"; +import type { Lesson } from './types'; export const lessonsEn: Lesson[] = [ { id: 1, - title: "Welcome to TypeScript", - level: "basic", + title: 'Welcome to TypeScript', + level: 'basic', content: - "TypeScript is a superset of JavaScript that adds static typing. " + + 'TypeScript is a superset of JavaScript that adds static typing. ' + 'With it, you define the "shape" of your data using interfaces, preventing ' + - "runtime errors. See the example: we create a `User` interface with " + - "two typed fields and instantiate an object that follows it.", + 'runtime errors. See the example: we create a `User` interface with ' + + 'two typed fields and instantiate an object that follows it.', task: "Try changing the user's name in the editor and click Compile & Run.", - hint: "Change the value of `name` inside the `user` object.", + hint: 'Change the value of `name` inside the `user` object.', starterCode: `interface User { name: string; id: number; @@ -26,14 +26,14 @@ console.log(\`Hello, \${user.name}! Your ID is \${user.id}.\`);`, }, { id: 2, - title: "Static Typing and Inference", - level: "basic", - content: - "TypeScript automatically infers types in many cases. When you define a variable " + - "with an initial value, TypeScript deduces its type. This is called type inference and " + - "makes the code more concise while maintaining safety.", - task: "Observe how TypeScript infers the type of the `message` variable.", - hint: "The type is inferred from the initial value.", + title: 'Static Typing and Inference', + level: 'basic', + content: + 'TypeScript automatically infers types in many cases. When you define a variable ' + + 'with an initial value, TypeScript deduces its type. This is called type inference and ' + + 'makes the code more concise while maintaining safety.', + task: 'Observe how TypeScript infers the type of the `message` variable.', + hint: 'The type is inferred from the initial value.', starterCode: `let message = "Hello, TypeScript!" let count = 42 let isActive = true @@ -49,13 +49,13 @@ console.log(isActive)`, }, { id: 3, - title: "Interfaces", - level: "basic", + title: 'Interfaces', + level: 'basic', content: - "Interfaces define the structure that objects must follow. They are fundamental in TypeScript " + - "to ensure objects have the correct properties with the right types.", - task: "Add an `email` property to the `Person` interface and the object.", - hint: "Add `email: string` to the interface.", + 'Interfaces define the structure that objects must follow. They are fundamental in TypeScript ' + + 'to ensure objects have the correct properties with the right types.', + task: 'Add an `email` property to the `Person` interface and the object.', + hint: 'Add `email: string` to the interface.', starterCode: `interface Person { name: string age: number @@ -70,13 +70,13 @@ console.log(\`\${person.name} is \${person.age} years old\`)`, }, { id: 4, - title: "Enums", - level: "basic", + title: 'Enums', + level: 'basic', content: - "Enums allow you to define a set of named constants. They are useful for " + - "representing states, directions, user roles, etc. TypeScript supports " + - "numeric (default) and string enums.", - task: "Add an `ADMIN` value to the `Role` enum and create a user with that role.", + 'Enums allow you to define a set of named constants. They are useful for ' + + 'representing states, directions, user roles, etc. TypeScript supports ' + + 'numeric (default) and string enums.', + task: 'Add an `ADMIN` value to the `Role` enum and create a user with that role.', hint: 'Add `ADMIN = "ADMIN"` to the enum and use `Role.ADMIN` in the object.', starterCode: `enum Direction { UP = "UP", @@ -106,14 +106,14 @@ console.log(\`\${player.name} (\${player.role}) is facing \${player.facing}\`)`, }, { id: 5, - title: "Type Aliases and Union Types", - level: "basic", - content: - "Type aliases create names for complex types. Union types (`|`) allow " + - "a variable to accept more than one type. This is much safer than using " + - "`any` while maintaining flexibility.", - task: "Create a type alias `Result` that is `string | number | boolean`.", - hint: "type Result = string | number | boolean;", + title: 'Type Aliases and Union Types', + level: 'basic', + content: + 'Type aliases create names for complex types. Union types (`|`) allow ' + + 'a variable to accept more than one type. This is much safer than using ' + + '`any` while maintaining flexibility.', + task: 'Create a type alias `Result` that is `string | number | boolean`.', + hint: 'type Result = string | number | boolean;', starterCode: `type ID = string | number type Status = "active" | "inactive" | "pending" @@ -136,14 +136,14 @@ console.log(getStatusLabel("active"))`, }, { id: 6, - title: "Type Assertions", - level: "basic", + title: 'Type Assertions', + level: 'basic', content: - "Type assertions tell TypeScript to treat a value as a specific type. " + + 'Type assertions tell TypeScript to treat a value as a specific type. ' + 'Use `as` or angle bracket syntax. It\'s like a "cast" in other languages, ' + "but doesn't convert the value at runtime.", - task: "Use type assertion to treat `input` as `string`.", - hint: "const str = input as string;", + task: 'Use type assertion to treat `input` as `string`.', + hint: 'const str = input as string;', starterCode: `let input: unknown = "hello world" const length1 = (input as string).length @@ -154,15 +154,15 @@ console.log("Length 2:", length2)`, }, { id: 7, - title: "Basic Types", - level: "basic", + title: 'Basic Types', + level: 'basic', content: - "TypeScript supports all JavaScript primitive types: `string`, `number`, " + - "`boolean`, `null`, `undefined`. It also offers `symbol`, `bigint` and the " + + 'TypeScript supports all JavaScript primitive types: `string`, `number`, ' + + '`boolean`, `null`, `undefined`. It also offers `symbol`, `bigint` and the ' + "type `void` for functions that don't return anything.", - task: "Create variables of the types you learned.", + task: 'Create variables of the types you learned.', hint: 'let name: string = "Alice";', - starterCode: `let name: string = "Alice" + starterCode: `{let name: string = "Alice" let age: number = 25 let isStudent: boolean = true let nothing: null = null @@ -170,15 +170,15 @@ let notDefined: undefined = undefined let id: symbol = Symbol("id") let bigNumber: bigint = 9007199254740991n -console.log(name, age, isStudent)`, +console.log(name, age, isStudent)}`, }, { id: 8, - title: "Arrays and Tuples", - level: "basic", + title: 'Arrays and Tuples', + level: 'basic', content: - "Arrays in TypeScript can be typed as `number[]` or `Array`. " + - "Tuples are arrays with a fixed size and specific types at each position: `[string, number]`.", + 'Arrays in TypeScript can be typed as `number[]` or `Array`. ' + + 'Tuples are arrays with a fixed size and specific types at each position: `[string, number]`.', task: "Create a tuple with a person's name and age.", hint: 'let person: [string, number] = ["Alice", 25];', starterCode: `const numbers: number[] = [1, 2, 3, 4, 5] @@ -193,13 +193,13 @@ console.log("Coords:", coords)`, }, { id: 9, - title: "Functions - Parameter and Return Typing", - level: "basic", + title: 'Functions - Parameter and Return Typing', + level: 'basic', content: - "Functions in TypeScript can have defined types for parameters and return. " + - "This ensures the function is called with the correct arguments and returns the expected value.", - task: "Add the return type `number` to the `soma` function.", - hint: "function soma(a: number, b: number): number", + 'Functions in TypeScript can have defined types for parameters and return. ' + + 'This ensures the function is called with the correct arguments and returns the expected value.', + task: 'Add the return type `number` to the `soma` function.', + hint: 'function soma(a: number, b: number): number', starterCode: `function greet(name: string): string { return \`Hello, \${name}!\` } @@ -216,14 +216,14 @@ console.log(add(10, 20))`, }, { id: 10, - title: "Optional and Default Parameters", - level: "basic", - content: - "Optional parameters use `?` (e.g., `name?: string`). Parameters with default values " + - "are automatically optional. The difference is that `undefined` is passed for optionals, " + - "while the default value is used for parameters with defaults.", - task: "Make the `age` parameter optional in the `introduce` function.", - hint: "function introduce(name: string, age?: number)", + title: 'Optional and Default Parameters', + level: 'basic', + content: + 'Optional parameters use `?` (e.g., `name?: string`). Parameters with default values ' + + 'are automatically optional. The difference is that `undefined` is passed for optionals, ' + + 'while the default value is used for parameters with defaults.', + task: 'Make the `age` parameter optional in the `introduce` function.', + hint: 'function introduce(name: string, age?: number)', starterCode: `function greet(name: string, greeting?: string): string { return greeting ? \`\${greeting}, \${name}!\` : \`Hello, \${name}!\` } @@ -242,12 +242,12 @@ console.log(introduce("Diana"))`, }, { id: 11, - title: "Utility Types - Partial, Required, Pick, Omit", - level: "basic", + title: 'Utility Types - Partial, Required, Pick, Omit', + level: 'basic', content: - "TypeScript includes built-in utility types that transform existing types: " + - "`Partial` makes all fields optional, `Required` makes them required, " + - "`Pick` selects fields, `Omit` removes fields.", + 'TypeScript includes built-in utility types that transform existing types: ' + + '`Partial` makes all fields optional, `Required` makes them required, ' + + '`Pick` selects fields, `Omit` removes fields.', task: 'Use `Omit` to create a `PublicUser` type.', hint: 'type PublicUser = Omit', starterCode: `interface User { @@ -275,14 +275,14 @@ console.log("Preview:", JSON.stringify(preview))`, }, { id: 12, - title: "Mapped Types", - level: "basic", - content: - "Mapped types allow you to create new types by transforming each property of an existing type. " + - "They use the syntax `{ [K in keyof T]: ... }`. Combined with `keyof` and modifiers " + - "(`readonly`, `?`), they are extremely powerful.", - task: "Create a mapped type `Nullable` that makes all properties optional.", - hint: "type Nullable = { [K in keyof T]?: T[K] | null; }", + title: 'Mapped Types', + level: 'basic', + content: + 'Mapped types allow you to create new types by transforming each property of an existing type. ' + + 'They use the syntax `{ [K in keyof T]: ... }`. Combined with `keyof` and modifiers ' + + '(`readonly`, `?`), they are extremely powerful.', + task: 'Create a mapped type `Nullable` that makes all properties optional.', + hint: 'type Nullable = { [K in keyof T]?: T[K] | null; }', starterCode: `interface Config { host: string port: number @@ -308,14 +308,14 @@ console.log("Partial:", JSON.stringify(partial))`, }, { id: 13, - title: "Conditional Types", - level: "basic", - content: - "Conditional types follow the syntax `T extends U ? X : Y` — if `T` is assignable to `U`, " + - "the resulting type is `X`, otherwise `Y`. With `infer`, you can extract types " + - "from inside other types.", - task: "Create a conditional type `IsArray` that returns `true` if T is an array.", - hint: "type IsArray = T extends any[] ? true : false", + title: 'Conditional Types', + level: 'basic', + content: + 'Conditional types follow the syntax `T extends U ? X : Y` — if `T` is assignable to `U`, ' + + 'the resulting type is `X`, otherwise `Y`. With `infer`, you can extract types ' + + 'from inside other types.', + task: 'Create a conditional type `IsArray` that returns `true` if T is an array.', + hint: 'type IsArray = T extends any[] ? true : false', starterCode: `type IsString = T extends string ? "yes" : "no" type A = IsString @@ -339,14 +339,14 @@ console.log("Result:", JSON.stringify(result))`, }, { id: 14, - title: "Decorators", - level: "basic", - content: - "Decorators are special functions that can be applied to classes, methods, " + - "properties and parameters using the `@decorator` syntax. They are widely used " + - "in frameworks like Angular, NestJS and TypeORM.", - task: "Create a `@readonly` decorator that makes a property non-editable.", - hint: "Use Object.defineProperty in the descriptor.", + title: 'Decorators', + level: 'basic', + content: + 'Decorators are special functions that can be applied to classes, methods, ' + + 'properties and parameters using the `@decorator` syntax. They are widely used ' + + 'in frameworks like Angular, NestJS and TypeORM.', + task: 'Create a `@readonly` decorator that makes a property non-editable.', + hint: 'Use Object.defineProperty in the descriptor.', starterCode: `function sealed(constructor: Function) { Object.seal(constructor) Object.seal(constructor.prototype) @@ -380,14 +380,14 @@ console.log("Fib(10):", calc.fibonacci(10))`, }, { id: 15, - title: "Generics - Introduction", - level: "basic", - content: - "Generics allow you to create components that work with any type while maintaining " + - "type safety. They are represented by `` and allow you to create reusable " + - "functions, classes and interfaces.", - task: "Create an `identity` function that returns the same value passed.", - hint: "function identity(value: T): T { return value; }", + title: 'Generics - Introduction', + level: 'basic', + content: + 'Generics allow you to create components that work with any type while maintaining ' + + 'type safety. They are represented by `` and allow you to create reusable ' + + 'functions, classes and interfaces.', + task: 'Create an `identity` function that returns the same value passed.', + hint: 'function identity(value: T): T { return value; }', starterCode: `function identity(value: T): T { return value } @@ -400,11 +400,11 @@ console.log(str, num, auto)`, }, { id: 16, - title: "Literal Types", - level: "basic", + title: 'Literal Types', + level: 'basic', content: - "TypeScript allows you to specify exact values a variable can have using literal types. " + - "This is useful when you want to restrict a value to a specific set of strings or numbers.", + 'TypeScript allows you to specify exact values a variable can have using literal types. ' + + 'This is useful when you want to restrict a value to a specific set of strings or numbers.', task: "Create a variable that can only have the values 'pending', 'loading' or 'success'.", hint: "type Status = 'pending' | 'loading' | 'success';", starterCode: `type Status = "pending" | "loading" | "success" @@ -416,13 +416,13 @@ console.log("Current status:", currentStatus)`, }, { id: 17, - title: "Function Overloads", - level: "basic", + title: 'Function Overloads', + level: 'basic', content: - "TypeScript supports function overloading, allowing you to define multiple signatures. " + - "TypeScript chooses the correct signature based on the arguments provided.", - task: "Create a `format` function that can format numbers and dates.", - hint: "Use multiple signatures before the implementation.", + 'TypeScript supports function overloading, allowing you to define multiple signatures. ' + + 'TypeScript chooses the correct signature based on the arguments provided.', + task: 'Create a `format` function that can format numbers and dates.', + hint: 'Use multiple signatures before the implementation.', starterCode: `function format(value: string): string function format(value: number, decimals?: number): string function format(value: Date): string @@ -445,13 +445,13 @@ console.log(format(new Date()))`, }, { id: 18, - title: "Modules and Imports/Exports", - level: "basic", + title: 'Modules and Imports/Exports', + level: 'basic', content: - "TypeScript has full support for the ES6 module system. Organize your code in separate files " + - "with explicit imports and exports for better encapsulation.", - task: "Create and export a function from a module, and import it in another.", - hint: "Use `export` and `import` in ES6 style.", + 'TypeScript has full support for the ES6 module system. Organize your code in separate files ' + + 'with explicit imports and exports for better encapsulation.', + task: 'Create and export a function from a module, and import it in another.', + hint: 'Use `export` and `import` in ES6 style.', starterCode: `export const capitalize = (str: string): string => { return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase() } @@ -471,13 +471,13 @@ console.log(trim(text))`, }, { id: 19, - title: "Namespaces", - level: "basic", + title: 'Namespaces', + level: 'basic', content: - "Namespaces group related code without polluting the global scope. Use `namespace` " + - "to organize code internally and `export` to expose members.", - task: "Create a `MathUtils` namespace with `add` and `multiply` functions.", - hint: "namespace MathUtils { export function add(...) }", + 'Namespaces group related code without polluting the global scope. Use `namespace` ' + + 'to organize code internally and `export` to expose members.', + task: 'Create a `MathUtils` namespace with `add` and `multiply` functions.', + hint: 'namespace MathUtils { export function add(...) }', starterCode: `namespace MathUtils { export function add(a: number, b: number): number { return a + b @@ -496,13 +496,13 @@ console.log("PI:", MathUtils.PI)`, }, { id: 20, - title: "Iterators and Generators", - level: "basic", + title: 'Iterators and Generators', + level: 'basic', content: - "TypeScript has full support for ES6 iterator and generator protocols. " + - "Generators (`function*`) provide an easy way to create functions that return sequences.", - task: "Create a generator function that yields numbers from 1 to N.", - hint: "Use function* and yield.", + 'TypeScript has full support for ES6 iterator and generator protocols. ' + + 'Generators (`function*`) provide an easy way to create functions that return sequences.', + task: 'Create a generator function that yields numbers from 1 to N.', + hint: 'Use function* and yield.', starterCode: `function* counter(limit: number) { let count = 1 while (count <= limit) { @@ -521,13 +521,13 @@ console.log("As array:", nums)`, }, { id: 21, - title: "Advanced Type Inference", - level: "advanced", + title: 'Advanced Type Inference', + level: 'advanced', content: - "TypeScript automatically infers types in many contexts. Inference works " + - "in variables, parameters, returns and uses control flow analysis and contextual typing.", - task: "Observe how TypeScript infers different types in the same example.", - hint: "Return type changes based on the parameter.", + 'TypeScript automatically infers types in many contexts. Inference works ' + + 'in variables, parameters, returns and uses control flow analysis and contextual typing.', + task: 'Observe how TypeScript infers different types in the same example.', + hint: 'Return type changes based on the parameter.', starterCode: `function processInput(input: string | number) { if (typeof input === "string") { return input.toUpperCase() @@ -547,13 +547,13 @@ console.log("Doubled:", doubled)`, }, { id: 22, - title: "Structural Type Compatibility", - level: "advanced", + title: 'Structural Type Compatibility', + level: 'advanced', content: - "TypeScript uses structural compatibility — two types are compatible if they have the same structure. " + - "This is different from nominal systems and makes TypeScript more flexible.", - task: "See how objects with compatible structures can be used interchangeably.", - hint: "If properties match, the type is compatible.", + 'TypeScript uses structural compatibility — two types are compatible if they have the same structure. ' + + 'This is different from nominal systems and makes TypeScript more flexible.', + task: 'See how objects with compatible structures can be used interchangeably.', + hint: 'If properties match, the type is compatible.', starterCode: `interface Point { x: number y: number @@ -578,13 +578,13 @@ console.log("Distance:", distanceFromOrigin(namedPoint))`, }, { id: 23, - title: "Working with JavaScript", - level: "basic", + title: 'Working with JavaScript', + level: 'basic', content: - "TypeScript was designed to gradually adopt existing JavaScript. " + - "Use `@ts-check` or `checkJs: true` in tsconfig.json to check .js files.", - task: "Understand how TypeScript checks JavaScript code.", - hint: "Use JSDoc to add types in .js files.", + 'TypeScript was designed to gradually adopt existing JavaScript. ' + + 'Use `@ts-check` or `checkJs: true` in tsconfig.json to check .js files.', + task: 'Understand how TypeScript checks JavaScript code.', + hint: 'Use JSDoc to add types in .js files.', starterCode: `// Simulating .js file verification // To enable: use // @ts-check at the top @@ -610,13 +610,13 @@ console.log("Factorial of 5:", factorial(5))`, }, { id: 24, - title: "Declaration Files (.d.ts)", - level: "advanced", + title: 'Declaration Files (.d.ts)', + level: 'advanced', content: - "Declaration files (.d.ts) provide type information for JavaScript libraries. " + - "Type definitions for popular libraries are in DefinitelyTyped (@types/*).", - task: "Create a simple declaration file for a function.", - hint: "declare function name(params): returnType;", + 'Declaration files (.d.ts) provide type information for JavaScript libraries. ' + + 'Type definitions for popular libraries are in DefinitelyTyped (@types/*).', + task: 'Create a simple declaration file for a function.', + hint: 'declare function name(params): returnType;', starterCode: `// Simulating a declaration file declare namespace Utils { @@ -642,12 +642,12 @@ console.log("Install types: npm install @types/lodash")`, }, { id: 25, - title: "Classes - Introduction", - level: "basic", + title: 'Classes - Introduction', + level: 'basic', content: - "Classes in TypeScript work like modern JavaScript but with full typing. " + - "You can define properties, methods, constructors and access modifiers.", - task: "Add a `sayHello` method to the `Person` class.", + 'Classes in TypeScript work like modern JavaScript but with full typing. ' + + 'You can define properties, methods, constructors and access modifiers.', + task: 'Add a `sayHello` method to the `Person` class.', hint: "sayHello() { return 'Hello, ' + this.name; }", starterCode: `class Person { name: string @@ -668,13 +668,13 @@ console.log(person.greet())`, }, { id: 26, - title: "Access Modifiers", - level: "basic", + title: 'Access Modifiers', + level: 'basic', content: - "TypeScript offers `public`, `private` and `protected` to control access to members. " + - "There is also `readonly` for properties that cannot be changed after initialization.", - task: "Make the `balance` property private and add a getter.", - hint: "private balance: number; public getBalance()", + 'TypeScript offers `public`, `private` and `protected` to control access to members. ' + + 'There is also `readonly` for properties that cannot be changed after initialization.', + task: 'Make the `balance` property private and add a getter.', + hint: 'private balance: number; public getBalance()', starterCode: `class BankAccount { public readonly id: number private balance: number @@ -705,13 +705,13 @@ console.log("New Balance:", account.getBalance())`, }, { id: 27, - title: "Class Inheritance", - level: "basic", + title: 'Class Inheritance', + level: 'basic', content: - "Classes can inherit from other classes using `extends`. The child class has access to " + - "public/protected methods and properties from the parent class and can override them.", - task: "Create a `Student` class that inherits from `Person`.", - hint: "class Student extends Person { }", + 'Classes can inherit from other classes using `extends`. The child class has access to ' + + 'public/protected methods and properties from the parent class and can override them.', + task: 'Create a `Student` class that inherits from `Person`.', + hint: 'class Student extends Person { }', starterCode: `class Person { constructor(public name: string, public age: number) {} @@ -736,13 +736,13 @@ console.log(student.study())`, }, { id: 28, - title: "Abstract Classes", - level: "basic", + title: 'Abstract Classes', + level: 'basic', content: - "Abstract classes cannot be instantiated directly, they serve as base for other classes. " + - "They can contain abstract methods (without implementation) that child classes must implement.", - task: "Create an abstract `Shape` class with abstract `area` method.", - hint: "abstract class Shape { abstract area(): number; }", + 'Abstract classes cannot be instantiated directly, they serve as base for other classes. ' + + 'They can contain abstract methods (without implementation) that child classes must implement.', + task: 'Create an abstract `Shape` class with abstract `area` method.', + hint: 'abstract class Shape { abstract area(): number; }', starterCode: `abstract class Shape { abstract area(): number abstract perimeter(): number @@ -788,12 +788,12 @@ console.log(circle.describe())`, }, { id: 29, - title: "Getters and Setters", - level: "basic", + title: 'Getters and Setters', + level: 'basic', content: - "Getters and setters allow precise control over property access. " + - "Useful for validation, computed values, or maintaining class invariants.", - task: "Create a `fullName` getter that returns the full name.", + 'Getters and setters allow precise control over property access. ' + + 'Useful for validation, computed values, or maintaining class invariants.', + task: 'Create a `fullName` getter that returns the full name.', hint: "get fullName(): string { return this.firstName + ' ' + this.lastName; }", starterCode: `class User { private _password: string = "" @@ -827,13 +827,13 @@ console.log("Password:", user.password)`, }, { id: 30, - title: "Static Members", - level: "basic", + title: 'Static Members', + level: 'basic', content: - "Static members belong to the class itself, not to instances. " + - "Accessed via `ClassName.property`, they are useful for constants or utility functions.", - task: "Add a static `createDefault` method to the `User` class.", - hint: "static createDefault(): User { }", + 'Static members belong to the class itself, not to instances. ' + + 'Accessed via `ClassName.property`, they are useful for constants or utility functions.', + task: 'Add a static `createDefault` method to the `User` class.', + hint: 'static createDefault(): User { }', starterCode: `class MathHelper { static readonly PI = 3.14159 @@ -853,14 +853,14 @@ console.log("Factorial 5:", MathHelper.factorial(5))`, }, { id: 31, - title: "Utility Types - Record, Partial, Readonly", - level: "advanced", - content: - "`Record` creates an object type with keys K and values V. " + - "`Partial` makes all properties optional. " + - "`Readonly` makes all properties read-only.", - task: "Create a `UserRecord` type using Record.", - hint: "type UserRecord = Record", + title: 'Utility Types - Record, Partial, Readonly', + level: 'advanced', + content: + '`Record` creates an object type with keys K and values V. ' + + '`Partial` makes all properties optional. ' + + '`Readonly` makes all properties read-only.', + task: 'Create a `UserRecord` type using Record.', + hint: 'type UserRecord = Record', starterCode: `interface User { id: number name: string @@ -884,13 +884,13 @@ console.log("Partial:", JSON.stringify(partial))`, }, { id: 32, - title: "Utility Types - Extract and Exclude", - level: "advanced", + title: 'Utility Types - Extract and Exclude', + level: 'advanced', content: - "`Extract` extracts from T the types that are assignable to U. " + - "`Exclude` removes from T the types that are assignable to U.", - task: "Use Extract to get only strings from a union type.", - hint: "type Strings = Extract", + '`Extract` extracts from T the types that are assignable to U. ' + + '`Exclude` removes from T the types that are assignable to U.', + task: 'Use Extract to get only strings from a union type.', + hint: 'type Strings = Extract', starterCode: `type T = string | number | boolean | null type Strings = Extract @@ -907,13 +907,13 @@ console.log("NotNull:", bool)`, }, { id: 33, - title: "Utility Types - ReturnType and Parameters", - level: "advanced", + title: 'Utility Types - ReturnType and Parameters', + level: 'advanced', content: - "`ReturnType` gets the return type of a function. " + - "`Parameters` gets the parameter types as a tuple.", - task: "Get the return type and parameters of a function.", - hint: "type R = ReturnType", + '`ReturnType` gets the return type of a function. ' + + '`Parameters` gets the parameter types as a tuple.', + task: 'Get the return type and parameters of a function.', + hint: 'type R = ReturnType', starterCode: `function createUser(name: string, age: number): { name: string; age: number; id: number } { return { name, age, id: Math.random() } } @@ -929,13 +929,13 @@ console.log("Args:", args)`, }, { id: 34, - title: "Type Guards", - level: "basic", + title: 'Type Guards', + level: 'basic', content: - "Type guards are expressions that refine the type of a variable. " + - "Use `typeof`, `instanceof`, or custom with `is` to filter types in unions.", - task: "Create a type guard to check if a value is a string.", - hint: "function isString(value: unknown): value is string { }", + 'Type guards are expressions that refine the type of a variable. ' + + 'Use `typeof`, `instanceof`, or custom with `is` to filter types in unions.', + task: 'Create a type guard to check if a value is a string.', + hint: 'function isString(value: unknown): value is string { }', starterCode: `function isString(value: unknown): value is string { return typeof value === "string" } @@ -969,13 +969,13 @@ if (isDog(pet)) { }, { id: 35, - title: "unknown and any", - level: "basic", + title: 'unknown and any', + level: 'basic', content: - "`any` completely disables type checking. " + + '`any` completely disables type checking. ' + '`unknown` is the "safe" type that represents any value — you must refine it before using.', - task: "Refine an `unknown` type to use it safely.", - hint: "Use type guards to check the type.", + task: 'Refine an `unknown` type to use it safely.', + hint: 'Use type guards to check the type.', starterCode: `let anyValue: any = "hello" let unknownValue: unknown = "world" @@ -992,13 +992,13 @@ console.log(str)`, }, { id: 36, - title: "never", - level: "basic", + title: 'never', + level: 'basic', content: - "`never` represents values that never occur. Functions that always throw errors " + - "or infinite loops have return type `never`. It is also used in exhaustive unions.", - task: "Create a function that throws an error and has return type never.", - hint: "function error(): never { throw new Error(); }", + '`never` represents values that never occur. Functions that always throw errors ' + + 'or infinite loops have return type `never`. It is also used in exhaustive unions.', + task: 'Create a function that throws an error and has return type never.', + hint: 'function error(): never { throw new Error(); }', starterCode: `function throwError(message: string): never { throw new Error(message) } @@ -1029,11 +1029,11 @@ console.log("Declaration merging works!")`, }, { id: 37, - title: "keyof and Index Access Types", - level: "advanced", + title: 'keyof and Index Access Types', + level: 'advanced', content: - "`keyof` gets the keys of a type as a union. " + - "Use `T[K]` to access the type of a specific property.", + '`keyof` gets the keys of a type as a union. ' + + 'Use `T[K]` to access the type of a specific property.', task: "Get the keys of User and the type of the 'name' property.", hint: 'type Keys = keyof User; type NameType = User["name"]', starterCode: `interface User { @@ -1058,13 +1058,13 @@ console.log(getProperty(user, "email"))`, }, { id: 38, - title: "Generic Constraints", - level: "basic", + title: 'Generic Constraints', + level: 'basic', content: - "Constraints use `extends` to limit the types that can be used with generics. " + - "This ensures the type has the necessary properties.", - task: "Create a generic that only accepts objects with a `length` property.", - hint: "function fn(arg: T)", + 'Constraints use `extends` to limit the types that can be used with generics. ' + + 'This ensures the type has the necessary properties.', + task: 'Create a generic that only accepts objects with a `length` property.', + hint: 'function fn(arg: T)', starterCode: `function getLength(arg: T): number { return arg.length } @@ -1082,13 +1082,13 @@ console.log("Merged:", JSON.stringify(result))`, }, { id: 39, - title: "Generic Classes", - level: "basic", + title: 'Generic Classes', + level: 'basic', content: - "Generic classes allow creating reusable components that work with different types. " + - "The type is specified when creating an instance of the class.", - task: "Create a class `Box` that stores a value.", - hint: "class Box { private content: T; }", + 'Generic classes allow creating reusable components that work with different types. ' + + 'The type is specified when creating an instance of the class.', + task: 'Create a class `Box` that stores a value.', + hint: 'class Box { private content: T; }', starterCode: `class Box { private content: T @@ -1116,13 +1116,13 @@ console.log("Updated:", numberBox.get())`, }, { id: 40, - title: "Generic Interfaces", - level: "basic", + title: 'Generic Interfaces', + level: 'basic', content: - "Generic interfaces define contracts that work with multiple types. " + - "They are the foundation of libraries like React, Zod, and Prisma.", - task: "Create a `Repository` interface with CRUD methods.", - hint: "interface Repository { findAll(): T[]; }", + 'Generic interfaces define contracts that work with multiple types. ' + + 'They are the foundation of libraries like React, Zod, and Prisma.', + task: 'Create a `Repository` interface with CRUD methods.', + hint: 'interface Repository { findAll(): T[]; }', starterCode: `interface Entity { id: number } @@ -1177,13 +1177,13 @@ console.log("Find 1:", repo.findById(1))`, }, { id: 41, - title: "Error Handling Typing", - level: "basic", + title: 'Error Handling Typing', + level: 'basic', content: - "TypeScript improves error handling with better inference in try/catch blocks. " + - "Specify the error type for better autocomplete.", - task: "Create a function that can throw errors and handle them.", - hint: "try { } catch (error) { if (error instanceof Error) { } }", + 'TypeScript improves error handling with better inference in try/catch blocks. ' + + 'Specify the error type for better autocomplete.', + task: 'Create a function that can throw errors and handle them.', + hint: 'try { } catch (error) { if (error instanceof Error) { } }', starterCode: `function divide(a: number, b: number): number { if (b === 0) { throw new Error("Division by zero is not allowed") @@ -1227,13 +1227,13 @@ try { }, { id: 42, - title: "Async/Await and Promises", - level: "basic", + title: 'Async/Await and Promises', + level: 'basic', content: - "TypeScript fully supports typed async/await. Async functions return Promises, " + - "and you can type the resolved value.", - task: "Create an async function that returns a typed user.", - hint: "async function fetchUser(): Promise { }", + 'TypeScript fully supports typed async/await. Async functions return Promises, ' + + 'and you can type the resolved value.', + task: 'Create an async function that returns a typed user.', + hint: 'async function fetchUser(): Promise { }', starterCode: `interface User { id: number name: string @@ -1269,13 +1269,13 @@ main()`, }, { id: 43, - title: "this in Types", - level: "basic", + title: 'this in Types', + level: 'basic', content: - "TypeScript allows typing `this` in methods. Use `this` as the first parameter " + - "to ensure methods are called in the correct context (fluent API).", - task: "Create a fluent API with methods that return `this`.", - hint: "add(name: string): this { }", + 'TypeScript allows typing `this` in methods. Use `this` as the first parameter ' + + 'to ensure methods are called in the correct context (fluent API).', + task: 'Create a fluent API with methods that return `this`.', + hint: 'add(name: string): this { }', starterCode: `class Builder { private parts: string[] = [] @@ -1328,13 +1328,13 @@ console.log("Calc result:", calc.result())`, }, { id: 44, - title: "Optional Chaining and Nullish Coalescing", - level: "basic", + title: 'Optional Chaining and Nullish Coalescing', + level: 'basic', content: - "`?.` accesses deep properties without error if something is null/undefined. " + - "`??` returns the right operand if the left is null/undefined.", - task: "Use optional chaining to access a nested property.", - hint: "user?.address?.city", + '`?.` accesses deep properties without error if something is null/undefined. ' + + '`??` returns the right operand if the left is null/undefined.', + task: 'Use optional chaining to access a nested property.', + hint: 'user?.address?.city', starterCode: `interface User { name: string address?: { @@ -1367,13 +1367,13 @@ console.log("Zero:", zero)`, }, { id: 45, - title: "Non-null Assertion Operator", - level: "basic", + title: 'Non-null Assertion Operator', + level: 'basic', content: - "`!` tells TypeScript that a value is not null/undefined. Use with caution — " + - "only when you are sure the value exists.", - task: "Use non-null assertion to access a guaranteed property.", - hint: "element!.value", + '`!` tells TypeScript that a value is not null/undefined. Use with caution — ' + + 'only when you are sure the value exists.', + task: 'Use non-null assertion to access a guaranteed property.', + hint: 'element!.value', starterCode: `function getElement(): HTMLInputElement | null { return document.createElement("input") } @@ -1391,13 +1391,13 @@ console.log("Result:", result)`, }, { id: 46, - title: "Type Casting vs Assertion", - level: "basic", + title: 'Type Casting vs Assertion', + level: 'basic', content: - "Type assertions (`as`) convert types. Use them when you know more about the type " + + 'Type assertions (`as`) convert types. Use them when you know more about the type ' + "than TypeScript does. Different from casting in other languages, it doesn't convert the value.", - task: "Use assertion to convert one type to another.", - hint: "const num = value as number", + task: 'Use assertion to convert one type to another.', + hint: 'const num = value as number', starterCode: `let input: unknown = "123" const strLength1 = (input as string).length @@ -1429,13 +1429,13 @@ processAnimal(dog)`, }, { id: 47, - title: "Template Literal Types", - level: "advanced", + title: 'Template Literal Types', + level: 'advanced', content: - "Template literal types create new types using string templates. " + - "Combine with infer to extract and manipulate strings in types.", - task: "Create a type that automatically creates getters.", - hint: "type Getters = { [K in keyof T as `get${K}`]: () => T[K] }", + 'Template literal types create new types using string templates. ' + + 'Combine with infer to extract and manipulate strings in types.', + task: 'Create a type that automatically creates getters.', + hint: 'type Getters = { [K in keyof T as `get${K}`]: () => T[K] }', starterCode: `type World = "world" type Greeting = \`hello \${World}\` @@ -1464,12 +1464,12 @@ console.log(getters.getAge())`, }, { id: 48, - title: "Discriminated Unions", - level: "basic", + title: 'Discriminated Unions', + level: 'basic', content: - "Create unions with a common property (discriminator) to make it easier for TypeScript " + - "to identify which union member is in use. Very useful for state management.", - task: "Create a discriminated union for file formats.", + 'Create unions with a common property (discriminator) to make it easier for TypeScript ' + + 'to identify which union member is in use. Very useful for state management.', + task: 'Create a discriminated union for file formats.', hint: 'type File = { type: "image", data: ... } | { type: "video", data: ... }', starterCode: `type Loading = { status: "loading" } type Success = { status: "success"; data: string } @@ -1501,13 +1501,13 @@ handleResult(errorResult)`, }, { id: 49, - title: "Mixin Classes", - level: "advanced", + title: 'Mixin Classes', + level: 'advanced', content: - "Mixins are functions that take a class and return a new class with extra functionality. " + - "Useful for composition when single inheritance is not enough.", - task: "Create a `Serializable` mixin that adds a toJSON method.", - hint: "function Serializable>(Base: T)", + 'Mixins are functions that take a class and return a new class with extra functionality. ' + + 'Useful for composition when single inheritance is not enough.', + task: 'Create a `Serializable` mixin that adds a toJSON method.', + hint: 'function Serializable>(Base: T)', starterCode: `type Constructor = new (...args: any[]) => T function Serializable>(Base: T) { @@ -1540,13 +1540,13 @@ console.log("User:", JSON.stringify(user, null, 2))`, }, { id: 50, - title: "Declaration Merging", - level: "advanced", + title: 'Declaration Merging', + level: 'advanced', content: 'TypeScript allows interfaces and namespaces with the same name to be "merged". ' + - "Interfaces are merged automatically, namespaces require `export`.", - task: "Create an interface that is merged with another.", - hint: "interface Animal { name: string; } interface Animal { age: number; }", + 'Interfaces are merged automatically, namespaces require `export`.', + task: 'Create an interface that is merged with another.', + hint: 'interface Animal { name: string; } interface Animal { age: number; }', starterCode: `interface User { name: string } @@ -1581,13 +1581,13 @@ console.log("Declaration merging works!")`, }, { id: 51, - title: "Type-safe Event Emitter", - level: "advanced", + title: 'Type-safe Event Emitter', + level: 'advanced', content: - "Create a type-safe event emitter that guarantees listeners and events match. " + - "Use generics to map event names to their payloads.", - task: "Create an EventMap type and implement an emitter.", - hint: "type Events = { event: payload }", + 'Create a type-safe event emitter that guarantees listeners and events match. ' + + 'Use generics to map event names to their payloads.', + task: 'Create an EventMap type and implement an emitter.', + hint: 'type Events = { event: payload }', starterCode: `type EventMap = { userJoined: { userId: number; name: string } userLeft: { userId: number } @@ -1629,13 +1629,13 @@ emitter.emit("message", { from: "Bob", text: "Hello!" })`, }, { id: 52, - title: "Builder Pattern with Generics", - level: "advanced", + title: 'Builder Pattern with Generics', + level: 'advanced', content: - "The Builder pattern allows you to construct complex objects step by step. " + - "With generics, we can ensure methods return the correct builder.", - task: "Implement a builder to create users with validation.", - hint: "Use this return for method chaining.", + 'The Builder pattern allows you to construct complex objects step by step. ' + + 'With generics, we can ensure methods return the correct builder.', + task: 'Implement a builder to create users with validation.', + hint: 'Use this return for method chaining.', starterCode: `class UserBuilder { private user: { name?: string; age?: number; email?: string } = {} @@ -1675,13 +1675,13 @@ console.log("Built user:", JSON.stringify(user))`, }, { id: 53, - title: "Currying and Function Composition", - level: "basic", + title: 'Currying and Function Composition', + level: 'basic', content: - "Currying transforms multi-arg functions into sequences of single-arg functions. " + - "Composition combines functions to create data pipelines.", - task: "Create curried functions and compose them.", - hint: "const add = (a: number) => (b: number) => a + b", + 'Currying transforms multi-arg functions into sequences of single-arg functions. ' + + 'Composition combines functions to create data pipelines.', + task: 'Create curried functions and compose them.', + hint: 'const add = (a: number) => (b: number) => a + b', starterCode: `const add = (a: number) => (b: number): number => a + b const multiply = (a: number) => (b: number): number => a * b const subtract = (a: number) => (b: number): number => a - b @@ -1707,13 +1707,13 @@ console.log("pipe(add10, double, subtract5)(5):", processNumber(5))`, }, { id: 54, - title: "Type-safe API Client", - level: "advanced", + title: 'Type-safe API Client', + level: 'advanced', content: - "Create an HTTP client that automatically infers response types. " + - "Use generics to type endpoints and responses.", - task: "Create a client with types for GET and POST.", - hint: "class ApiClient { get(url): Promise }", + 'Create an HTTP client that automatically infers response types. ' + + 'Use generics to type endpoints and responses.', + task: 'Create a client with types for GET and POST.', + hint: 'class ApiClient { get(url): Promise }', starterCode: `interface User { id: number name: string @@ -1760,13 +1760,13 @@ createUser({ name: "Alice", email: "alice@example.com" }) }, { id: 55, - title: "Flattened Union Types", - level: "advanced", + title: 'Flattened Union Types', + level: 'advanced', content: - "Create complex union types and use distribution to transform them. " + - "Useful for automatically creating literal string unions.", - task: "Create a union of HTTP methods from an array.", - hint: "type Method = typeof methods[number]", + 'Create complex union types and use distribution to transform them. ' + + 'Useful for automatically creating literal string unions.', + task: 'Create a union of HTTP methods from an array.', + hint: 'type Method = typeof methods[number]', starterCode: `const methods = ["get", "post", "put", "delete", "patch"] as const type HttpMethod = typeof methods[number] @@ -1807,13 +1807,13 @@ console.log("Variants:", variants)`, }, { id: 56, - title: "Immutable Update Patterns", - level: "basic", + title: 'Immutable Update Patterns', + level: 'basic', content: - "Update objects and arrays immutably to avoid accidental mutations. " + - "Use spread operator and methods that return new arrays.", - task: "Update a nested object immutably.", - hint: "Use spread to create new references.", + 'Update objects and arrays immutably to avoid accidental mutations. ' + + 'Use spread operator and methods that return new arrays.', + task: 'Update a nested object immutably.', + hint: 'Use spread to create new references.', starterCode: `interface State { user: { profile: { @@ -1863,13 +1863,13 @@ console.log("Same reference?", state === newState)`, }, { id: 57, - title: "Recursive Types", - level: "advanced", + title: 'Recursive Types', + level: 'advanced', content: - "Recursive types allow you to represent hierarchical structures like trees and lists. " + - "Useful for JSON, ASTs, and nested data structures.", - task: "Create a type for a directory tree.", - hint: "interface TreeNode { name: string; children?: TreeNode[] }", + 'Recursive types allow you to represent hierarchical structures like trees and lists. ' + + 'Useful for JSON, ASTs, and nested data structures.', + task: 'Create a type for a directory tree.', + hint: 'interface TreeNode { name: string; children?: TreeNode[] }', starterCode: `interface TreeNode { name: string type: "file" | "folder" @@ -1919,12 +1919,12 @@ console.log("JSON:", JSON.stringify(json, null, 2))`, }, { id: 58, - title: "Branded Types", - level: "advanced", + title: 'Branded Types', + level: 'advanced', content: 'Branded types add "tags" to existing types to distinguish primitive types. ' + - "Useful for IDs, currencies, and values that need semantic validation.", - task: "Create branded types for UserId and OrderId.", + 'Useful for IDs, currencies, and values that need semantic validation.', + task: 'Create branded types for UserId and OrderId.', hint: 'type UserId = string & { __brand: "UserId" }', starterCode: `type UserId = string & { readonly __brand: "UserId" } type OrderId = string & { readonly __brand: "OrderId" } @@ -1962,12 +1962,12 @@ console.log("Email:", email)`, }, { id: 59, - title: "Finite State Machines", - level: "advanced", + title: 'Finite State Machines', + level: 'advanced', content: - "State machines define a finite number of states and transitions between them. " + - "TypeScript can ensure only valid transitions occur.", - task: "Create a state machine for an order.", + 'State machines define a finite number of states and transitions between them. ' + + 'TypeScript can ensure only valid transitions occur.', + task: 'Create a state machine for an order.', hint: 'type State = "pending" | "shipped" | "delivered"', starterCode: `type OrderState = "pending" | "confirmed" | "shipped" | "delivered" | "cancelled" @@ -2022,12 +2022,12 @@ console.log("After deliver:", order.state)`, }, { id: 60, - title: "Weak Types and Type Guards", - level: "advanced", + title: 'Weak Types and Type Guards', + level: 'advanced', content: - "Weak types are types with all properties optional. " + - "TypeScript has special checking to ensure at least one property is provided.", - task: "Create a function that accepts only valid options.", + 'Weak types are types with all properties optional. ' + + 'TypeScript has special checking to ensure at least one property is provided.', + task: 'Create a function that accepts only valid options.', hint: 'Use "at least one" constraint with keyof', starterCode: `type Options = { timeout?: number @@ -2049,13 +2049,13 @@ configure({ timeout: 1000, retries: 5 })`, }, { id: 61, - title: "Proxy and Interception", - level: "advanced", + title: 'Proxy and Interception', + level: 'advanced', content: - "Proxy allows you to intercept operations like reading, writing, and method invocation. " + - "Useful for logging, validation, and lazy loading.", - task: "Create a proxy to validate properties.", - hint: "new Proxy(target, { get, set })", + 'Proxy allows you to intercept operations like reading, writing, and method invocation. ' + + 'Useful for logging, validation, and lazy loading.', + task: 'Create a proxy to validate properties.', + hint: 'new Proxy(target, { get, set })', starterCode: `interface User { name: string age: number @@ -2095,12 +2095,12 @@ try { }, { id: 62, - title: "Symbol and Metadata", - level: "basic", + title: 'Symbol and Metadata', + level: 'basic', content: - "Symbols are unique values that can serve as property keys. " + + 'Symbols are unique values that can serve as property keys. ' + 'Useful for creating "hidden" properties and for reflection.', - task: "Use Symbol to create a private property.", + task: 'Use Symbol to create a private property.', hint: 'const privateKey = Symbol("private")', starterCode: `const nameKey = Symbol("name") const ageKey = Symbol("age") @@ -2137,13 +2137,13 @@ console.log("Cached:", cache.get(key1))`, }, { id: 63, - title: "Asserts Type Guards", - level: "advanced", + title: 'Asserts Type Guards', + level: 'advanced', content: - "Asserts type guards are functions that verify and refine types, " + - "throwing an error if the condition is not met.", - task: "Create an assert that checks if a value is a positive number.", - hint: "function assert(condition, message)", + 'Asserts type guards are functions that verify and refine types, ' + + 'throwing an error if the condition is not met.', + task: 'Create an assert that checks if a value is a positive number.', + hint: 'function assert(condition, message)', starterCode: `function assert(condition: boolean, message: string): asserts condition { if (!condition) { throw new Error(message) @@ -2177,13 +2177,13 @@ console.log("Data length:", data.length)`, }, { id: 64, - title: "Infer with Conditional Types", - level: "advanced", + title: 'Infer with Conditional Types', + level: 'advanced', content: - "`infer` extracts types from inside other types. " + - "It can extract types from functions, arrays, promises, and objects.", - task: "Extract the element type from an array.", - hint: "type ArrayElement = T extends (infer U)[] ? U : never", + '`infer` extracts types from inside other types. ' + + 'It can extract types from functions, arrays, promises, and objects.', + task: 'Extract the element type from an array.', + hint: 'type ArrayElement = T extends (infer U)[] ? U : never', starterCode: `type ReturnTypeOf = T extends (...args: any[]) => infer R ? R : never type ParametersOf = T extends (...args: infer P) => any ? P : never type ArrayElement = T extends (infer U)[] ? U : never @@ -2216,13 +2216,13 @@ console.log("Promise:", pv)`, }, { id: 65, - title: "Type-safe Event Bus", - level: "advanced", + title: 'Type-safe Event Bus', + level: 'advanced', content: - "Create an event bus that guarantees type safety for events and handlers. " + - "Use mapped types to derive event types.", - task: "Implement an event bus with type-safe subscribe and emit.", - hint: "Use keyof and generics for inference.", + 'Create an event bus that guarantees type safety for events and handlers. ' + + 'Use mapped types to derive event types.', + task: 'Implement an event bus with type-safe subscribe and emit.', + hint: 'Use keyof and generics for inference.', starterCode: `type Events = { login: { userId: number; timestamp: Date } logout: { userId: number } @@ -2277,13 +2277,13 @@ bus.emit("purchase", { userId: 1, amount: 99.99 })`, }, { id: 66, - title: "Deep Readonly", - level: "advanced", + title: 'Deep Readonly', + level: 'advanced', content: - "Create a type that makes all nested properties readonly recursively. " + - "Useful for ensuring immutability in complex objects.", - task: "Create a DeepReadonly type.", - hint: "type DeepReadonly = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K] }", + 'Create a type that makes all nested properties readonly recursively. ' + + 'Useful for ensuring immutability in complex objects.', + task: 'Create a DeepReadonly type.', + hint: 'type DeepReadonly = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K] }', starterCode: `type DeepReadonly = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K] } @@ -2315,13 +2315,13 @@ console.log("Company:", JSON.stringify(company, null, 2))`, }, { id: 67, - title: "Strict Null Checks in Filters", - level: "basic", + title: 'Strict Null Checks in Filters', + level: 'basic', content: - "Filtering arrays can create union types with undefined. " + - "Learn to use type guards to properly refine them.", - task: "Filter null values and refine the type.", - hint: "arr.filter((x): x is Type => x !== null)", + 'Filtering arrays can create union types with undefined. ' + + 'Learn to use type guards to properly refine them.', + task: 'Filter null values and refine the type.', + hint: 'arr.filter((x): x is Type => x !== null)', starterCode: `interface User { id: number name: string @@ -2357,12 +2357,12 @@ if (result) { }, { id: 68, - title: "Enum vs Union vs Const Object", - level: "basic", + title: 'Enum vs Union vs Const Object', + level: 'basic', content: - "Compare enums, union types, and const objects to understand when to use each. " + - "Each approach has pros and cons in terms of runtime and type safety.", - task: "Convert an enum to a union type and compare.", + 'Compare enums, union types, and const objects to understand when to use each. ' + + 'Each approach has pros and cons in terms of runtime and type safety.', + task: 'Convert an enum to a union type and compare.', hint: 'type Direction = "N" | "S" | "E" | "W"', starterCode: `enum DirectionEnum { North = "N", @@ -2397,12 +2397,13 @@ console.log("All approaches work!")`, }, { id: 69, - title: "Type-safe CSV Parser", - level: "advanced", + title: 'Type-safe CSV Parser', + level: 'advanced', content: - "Create a CSV parser that infers column types. " + "Use generics to map headers to types.", - task: "Parse CSV and infer column types.", - hint: "function parseCSV(csv: string): T[]", + 'Create a CSV parser that infers column types. ' + + 'Use generics to map headers to types.', + task: 'Parse CSV and infer column types.', + hint: 'function parseCSV(csv: string): T[]', starterCode: `interface User { id: number name: string @@ -2446,13 +2447,13 @@ console.log("First user:", first)`, }, { id: 70, - title: "Schema Validation with Mapped Types", - level: "advanced", + title: 'Schema Validation with Mapped Types', + level: 'advanced', content: - "Create a schema validator that checks objects against type definitions. " + - "Use mapped types to transform the schema into validators.", - task: "Validate an object against a schema.", - hint: "Use Record to map fields to validators.", + 'Create a schema validator that checks objects against type definitions. ' + + 'Use mapped types to transform the schema into validators.', + task: 'Validate an object against a schema.', + hint: 'Use Record to map fields to validators.', starterCode: `type Validator = (value: unknown) => T type Schema = { @@ -2506,13 +2507,13 @@ console.log("Validated:", validated)`, }, { id: 71, - title: "Polymorphic this Types", - level: "advanced", + title: 'Polymorphic this Types', + level: 'advanced', content: - "Use `this` as return type to create fluent APIs where methods return " + - "the concrete class, not the base class. Useful for inheritance.", - task: "Create a fluent API with polymorphic this.", - hint: "class Builder { add(): this { } }", + 'Use `this` as return type to create fluent APIs where methods return ' + + 'the concrete class, not the base class. Useful for inheritance.', + task: 'Create a fluent API with polymorphic this.', + hint: 'class Builder { add(): this { } }', starterCode: `class Builder { protected parts: string[] = [] @@ -2575,13 +2576,13 @@ console.log("Result:", calc.result())`, }, { id: 72, - title: "Tuple Types in Functions", - level: "basic", + title: 'Tuple Types in Functions', + level: 'basic', content: - "Tuples can be used to type function parameters with multiple values. " + - "Useful for functions that return multiple values.", - task: "Create a function that returns name and age as a tuple.", - hint: "function getPerson(): [string, number] { }", + 'Tuples can be used to type function parameters with multiple values. ' + + 'Useful for functions that return multiple values.', + task: 'Create a function that returns name and age as a tuple.', + hint: 'function getPerson(): [string, number] { }', starterCode: `function getUser(): [string, number, boolean] { return ["Alice", 25, true] } @@ -2618,13 +2619,13 @@ console.log("Parsed:", date)`, }, { id: 73, - title: "Interface vs Type Alias", - level: "basic", + title: 'Interface vs Type Alias', + level: 'basic', content: - "Interfaces are better for objects and classes, allowing extends and merge. " + - "Type aliases are better for unions, intersections, and primitive types.", - task: "Compare interface and type for the same object.", - hint: "interface for objects, type for unions", + 'Interfaces are better for objects and classes, allowing extends and merge. ' + + 'Type aliases are better for unions, intersections, and primitive types.', + task: 'Compare interface and type for the same object.', + hint: 'interface for objects, type for unions', starterCode: `interface UserI { name: string age: number @@ -2661,12 +2662,12 @@ console.log("Pair:", pair)`, }, { id: 74, - title: "Module Resolution", - level: "advanced", + title: 'Module Resolution', + level: 'advanced', content: - "TypeScript resolves modules in different ways: classic, node, node16, nodenext. " + - "Understand the differences to configure projects correctly.", - task: "Configure paths and baseUrl for imports.", + 'TypeScript resolves modules in different ways: classic, node, node16, nodenext. ' + + 'Understand the differences to configure projects correctly.', + task: 'Configure paths and baseUrl for imports.', hint: 'Configure "baseUrl" and "paths" in tsconfig.json', starterCode: `// Simulating tsconfig paths // { @@ -2702,12 +2703,12 @@ console.log("Resolved @/components:", resolvePath("@/components"))`, }, { id: 75, - title: "Ambient Modules and Triple-Slash", - level: "advanced", + title: 'Ambient Modules and Triple-Slash', + level: 'advanced', content: - "Use triple-slash directives to declare module dependencies. " + - "Useful for including types and modules in compiled files.", - task: "Use triple-slash to declare a module.", + 'Use triple-slash directives to declare module dependencies. ' + + 'Useful for including types and modules in compiled files.', + task: 'Use triple-slash to declare a module.', hint: '/// ', starterCode: `/// @@ -2730,13 +2731,13 @@ console.log("Ambient declarations loaded!")`, }, { id: 76, - title: "Union Narrowing with never", - level: "advanced", + title: 'Union Narrowing with never', + level: 'advanced', content: - "Use `never` in unions to force TypeScript to check all cases. " + - "Useful in exhaustive switch statements.", - task: "Create an exhaustive switch.", - hint: "default: const _: never = value", + 'Use `never` in unions to force TypeScript to check all cases. ' + + 'Useful in exhaustive switch statements.', + task: 'Create an exhaustive switch.', + hint: 'default: const _: never = value', starterCode: `type Shape = | { kind: "circle"; radius: number } | { kind: "square"; side: number } @@ -2766,13 +2767,13 @@ shapes.forEach(s => console.log(\`Area: \${area(s).toFixed(2)}\`))`, }, { id: 77, - title: "Type-safe Event Listeners", - level: "advanced", + title: 'Type-safe Event Listeners', + level: 'advanced', content: - "Create functions that add event listeners with full type safety. " + - "The handler should have the correct type based on the event.", - task: "Create a type-safe addEventListener function.", - hint: "Use generics to infer the handler type.", + 'Create functions that add event listeners with full type safety. ' + + 'The handler should have the correct type based on the event.', + task: 'Create a type-safe addEventListener function.', + hint: 'Use generics to infer the handler type.', starterCode: `type EventMap = { click: { x: number; y: number } keydown: { key: string } @@ -2809,13 +2810,13 @@ on("focus", () => console.log("focused"))`, }, { id: 78, - title: "Intersection Types with Mixins", - level: "advanced", + title: 'Intersection Types with Mixins', + level: 'advanced', content: - "Intersection types combine multiple types into one. " + - "Useful for adding functionality via mixins or creating complex types.", - task: "Create a type that is both Serializable and Validatable.", - hint: "type T = Serializable & Validatable", + 'Intersection types combine multiple types into one. ' + + 'Useful for adding functionality via mixins or creating complex types.', + task: 'Create a type that is both Serializable and Validatable.', + hint: 'type T = Serializable & Validatable', starterCode: `interface Serializable { toJSON(): Record } @@ -2870,13 +2871,13 @@ io.write("hello")`, }, { id: 79, - title: "Type-safe Console Methods", - level: "basic", + title: 'Type-safe Console Methods', + level: 'basic', content: "TypeScript doesn't check console by default. " + - "Create type-safe wrappers for consistent logging.", - task: "Create type-safe logging functions.", - hint: "function log(message: T): void", + 'Create type-safe wrappers for consistent logging.', + task: 'Create type-safe logging functions.', + hint: 'function log(message: T): void', starterCode: `function log(message: T): void { console.log(\`[LOG] \${message}\`) } @@ -2906,13 +2907,13 @@ console.log("Result:", result)`, }, { id: 80, - title: "Simple Pattern Matching", - level: "basic", + title: 'Simple Pattern Matching', + level: 'basic', content: - "Implement simple pattern matching with generics. " + - "Similar to match in functional languages.", - task: "Create a match function that executes patterns.", - hint: "function match(value: T, patterns: Record): R", + 'Implement simple pattern matching with generics. ' + + 'Similar to match in functional languages.', + task: 'Create a match function that executes patterns.', + hint: 'function match(value: T, patterns: Record): R', starterCode: `function match(value: T, patterns: Record): R { if (value in patterns) { return patterns[value] @@ -2957,13 +2958,13 @@ console.log(reduce({ type: "reset" }))`, }, { id: 81, - title: "Variadic Tuple Types", - level: "advanced", + title: 'Variadic Tuple Types', + level: 'advanced', content: - "Variadic tuples allow creating types that accept a variable number of elements. " + - "Useful for type concatenation and tail recursion.", - task: "Create a type that concatenates tuples.", - hint: "type Concat = [...T, ...U]", + 'Variadic tuples allow creating types that accept a variable number of elements. ' + + 'Useful for type concatenation and tail recursion.', + task: 'Create a type that concatenates tuples.', + hint: 'type Concat = [...T, ...U]', starterCode: `type Concat = [...T, ...U] type A = Concat<[1, 2], [3, 4]> @@ -2989,13 +2990,13 @@ const d: D = [2, 3]`, }, { id: 82, - title: "Awaited Type for Promises", - level: "advanced", + title: 'Awaited Type for Promises', + level: 'advanced', content: - "The utility type `Awaited` extracts the resolved type of a Promise. " + - "It works recursively for nested Promises.", - task: "Use Awaited to type the result of async functions.", - hint: "type Result = Awaited>", + 'The utility type `Awaited` extracts the resolved type of a Promise. ' + + 'It works recursively for nested Promises.', + task: 'Use Awaited to type the result of async functions.', + hint: 'type Result = Awaited>', starterCode: `type Awaited = T extends Promise ? Awaited : T async function fetchUser(): Promise<{ id: number; name: string }> { @@ -3024,11 +3025,11 @@ getData()`, }, { id: 83, - title: "Brand Keys in Mapped Types", - level: "advanced", + title: 'Brand Keys in Mapped Types', + level: 'advanced', content: - "Use template literal types in mapped types to create key transformations. " + - "Useful for adding prefixes/suffixes or converting conventions.", + 'Use template literal types in mapped types to create key transformations. ' + + 'Useful for adding prefixes/suffixes or converting conventions.', task: "Create a mapped type that adds 'get' prefix to methods.", hint: "type WithGetters = { [K in keyof T as 'get' + K]: () => T[K] }", starterCode: `type WithGetters = { @@ -3068,13 +3069,13 @@ setters.setName("Bob")`, }, { id: 84, - title: "Type-safe React-like setState", - level: "advanced", + title: 'Type-safe React-like setState', + level: 'advanced', content: "Implement a state hook similar to React's useState. " + - "The setter should allow partial updates and infer types correctly.", - task: "Create a simplified useState with inferred types.", - hint: "function useState(initial: T): [() => T, (value: T | ((prev: T) => T)) => void]", + 'The setter should allow partial updates and infer types correctly.', + task: 'Create a simplified useState with inferred types.', + hint: 'function useState(initial: T): [() => T, (value: T | ((prev: T) => T)) => void]', starterCode: `function useState(initial: T) { let state = initial @@ -3107,13 +3108,13 @@ console.log("Final count:", count())`, }, { id: 85, - title: "Deep Partial Type", - level: "advanced", + title: 'Deep Partial Type', + level: 'advanced', content: - "Partial makes first-level properties optional. " + - "DeepPartial makes ALL nested properties optional recursively.", - task: "Create a DeepPartial type.", - hint: "type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] }", + 'Partial makes first-level properties optional. ' + + 'DeepPartial makes ALL nested properties optional recursively.', + task: 'Create a DeepPartial type.', + hint: 'type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] }', starterCode: `type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] } @@ -3167,13 +3168,13 @@ function updateCompany(current: Company, updates: PartialCompany): Company { }, { id: 86, - title: "Extract Keys by Value Type", - level: "advanced", + title: 'Extract Keys by Value Type', + level: 'advanced', content: - "Create a type that extracts keys from an object based on the type of its values. " + - "Useful for finding fields of a certain type.", - task: "Extract keys whose values are of type string.", - hint: "type KeysOfType = { [K in keyof T]: T[K] extends U ? K : never }[keyof T]", + 'Create a type that extracts keys from an object based on the type of its values. ' + + 'Useful for finding fields of a certain type.', + task: 'Extract keys whose values are of type string.', + hint: 'type KeysOfType = { [K in keyof T]: T[K] extends U ? K : never }[keyof T]', starterCode: `type KeysOfType = { [K in keyof T]: T[K] extends U ? K : never }[keyof T] @@ -3216,12 +3217,12 @@ console.log("Numbers:", numbers)`, }, { id: 87, - title: "Type-safe Redux-like Reducer", - level: "advanced", + title: 'Type-safe Redux-like Reducer', + level: 'advanced', content: - "Implement a type-safe reducer similar to Redux. " + - "The action type determines which payloads are valid.", - task: "Create a reducer with type-safe actions.", + 'Implement a type-safe reducer similar to Redux. ' + + 'The action type determines which payloads are valid.', + task: 'Create a reducer with type-safe actions.', hint: 'type Action = { type: "TYPE"; payload: T }', starterCode: `type Action = | { type: "increment"; payload: number } @@ -3272,13 +3273,13 @@ console.log("After reset:", state.count)`, }, { id: 88, - title: "Constructor Parameters Type", - level: "advanced", + title: 'Constructor Parameters Type', + level: 'advanced', content: "`ConstructorParameters` extracts the parameter types of T's constructor. " + - "Useful for creating factories and dependency injection.", - task: "Use ConstructorParameters to create a factory.", - hint: "type CtorParams = ConstructorParameters", + 'Useful for creating factories and dependency injection.', + task: 'Use ConstructorParameters to create a factory.', + hint: 'type CtorParams = ConstructorParameters', starterCode: `type ConstructorParameters any> = T extends new (...args: infer P) => any ? P : never @@ -3319,13 +3320,13 @@ console.log("Product:", product.name, product.price)`, }, { id: 89, - title: "Optional Keys and Required Keys", - level: "advanced", + title: 'Optional Keys and Required Keys', + level: 'advanced', content: - "`Required` makes all properties required. " + - "`Optional` (custom) can do the opposite, or create types that have only optionals.", - task: "Extract optional and required keys separately.", - hint: "type OptionalKeys = { [K in keyof T]: T extends { [K]: T[K] } ? never : K }[keyof T]", + '`Required` makes all properties required. ' + + '`Optional` (custom) can do the opposite, or create types that have only optionals.', + task: 'Extract optional and required keys separately.', + hint: 'type OptionalKeys = { [K in keyof T]: T extends { [K]: T[K] } ? never : K }[keyof T]', starterCode: `type OptionalKeys = { [K in keyof T]: {} extends Pick ? K : never }[keyof T] @@ -3363,13 +3364,13 @@ console.log("Validation:", result)`, }, { id: 90, - title: "Type-safe Event Bus Final", - level: "advanced", + title: 'Type-safe Event Bus Final', + level: 'advanced', content: - "Combine everything: generics, conditional types, and mapped types " + - "to create a completely type-safe event bus.", - task: "Create an event bus with inferred handlers.", - hint: "Use infer to extract event types.", + 'Combine everything: generics, conditional types, and mapped types ' + + 'to create a completely type-safe event bus.', + task: 'Create an event bus with inferred handlers.', + hint: 'Use infer to extract event types.', starterCode: `type EventMap = Record type EventReceiver = (params: T) => void @@ -3421,13 +3422,13 @@ bus.emit("purchase", { amount: 99.99, item: "E-book" })`, }, { id: 91, - title: "Omit vs Exclude", - level: "basic", + title: 'Omit vs Exclude', + level: 'basic', content: - "`Omit` removes properties from an object type. " + - "`Exclude` removes types from a union. Understand the difference.", - task: "Use Omit for objects and Exclude for unions.", - hint: "Omit for objects, Exclude for unions", + '`Omit` removes properties from an object type. ' + + '`Exclude` removes types from a union. Understand the difference.', + task: 'Use Omit for objects and Exclude for unions.', + hint: 'Omit for objects, Exclude for unions', starterCode: `interface User { id: number name: string @@ -3461,13 +3462,13 @@ console.log("Primary colors:", primaries)`, }, { id: 92, - title: "Typed Object.entries and Object.keys", - level: "basic", + title: 'Typed Object.entries and Object.keys', + level: 'basic', content: - "Object.entries and Object.keys return `string[]` by default. " + - "Use assertion or generics to type them correctly.", - task: "Iterate over an object with correct types.", - hint: "Use as Array<[keyof T, T[keyof T]]>", + 'Object.entries and Object.keys return `string[]` by default. ' + + 'Use assertion or generics to type them correctly.', + task: 'Iterate over an object with correct types.', + hint: 'Use as Array<[keyof T, T[keyof T]]>', starterCode: `interface User { id: number name: string @@ -3502,13 +3503,13 @@ typedEntries({ a: 1, b: 2, c: 3 }).forEach(([k, v]) => { }, { id: 93, - title: "Strict Property Initialization", - level: "basic", + title: 'Strict Property Initialization', + level: 'basic', content: - "With strictPropertyInitialization, class properties must be initialized " + - "in the constructor or with initialization shorthand.", - task: "Initialize properties correctly.", - hint: "Use constructor or initialization shorthand.", + 'With strictPropertyInitialization, class properties must be initialized ' + + 'in the constructor or with initialization shorthand.', + task: 'Initialize properties correctly.', + hint: 'Use constructor or initialization shorthand.', starterCode: `class User { name: string age: number @@ -3553,13 +3554,13 @@ console.log("Name:", opt.name)`, }, { id: 94, - title: "Type-safe Fetch Wrapper", - level: "advanced", + title: 'Type-safe Fetch Wrapper', + level: 'advanced', content: - "Create a type-safe wrapper for fetch that infers the response type. " + - "Supports JSON, text, and status checking.", - task: "Create a type-safe fetchJson function.", - hint: "async function fetchJson(url: string): Promise", + 'Create a type-safe wrapper for fetch that infers the response type. ' + + 'Supports JSON, text, and status checking.', + task: 'Create a type-safe fetchJson function.', + hint: 'async function fetchJson(url: string): Promise', starterCode: `async function fetchJson( url: string, options?: RequestInit @@ -3610,13 +3611,13 @@ main()`, }, { id: 95, - title: "Type-safe Route Handler", - level: "advanced", + title: 'Type-safe Route Handler', + level: 'advanced', content: - "Create a type-safe router where each route has its handler with specific types. " + - "The handler receives only the parameters defined for that route.", - task: "Create type-safe route handlers.", - hint: "Use Record to map routes to handlers.", + 'Create a type-safe router where each route has its handler with specific types. ' + + 'The handler receives only the parameters defined for that route.', + task: 'Create type-safe route handlers.', + hint: 'Use Record to map routes to handlers.', starterCode: `type RouteHandler = (params: T) => string | Promise interface Route { @@ -3671,12 +3672,12 @@ console.log(matchRoute("/posts/456?draft=true", routes))`, }, { id: 96, - title: "Generic Record Factory", - level: "advanced", + title: 'Generic Record Factory', + level: 'advanced', content: - "Create a factory that generates typed objects with useful methods. " + - "The return type should be completely inferred.", - task: "Create a factory to generate objects with IDs.", + 'Create a factory that generates typed objects with useful methods. ' + + 'The return type should be completely inferred.', + task: 'Create a factory to generate objects with IDs.', hint: 'function create(data: Omit): T & { id: string }', starterCode: `function createEntity( data: T @@ -3732,13 +3733,13 @@ console.log("Numbers:", [...numbers])`, }, { id: 97, - title: "Reverse Engineering Types", - level: "advanced", + title: 'Reverse Engineering Types', + level: 'advanced', content: - "Given an object, derive its type automatically. " + - "Use `typeof` to create types from values.", - task: "Use typeof to create types from objects.", - hint: "type T = typeof myObject", + 'Given an object, derive its type automatically. ' + + 'Use `typeof` to create types from values.', + task: 'Use typeof to create types from objects.', + hint: 'type T = typeof myObject', starterCode: `const user = { id: 1, name: "Alice", @@ -3788,12 +3789,12 @@ type Method = typeof constObj.GET | typeof constObj.POST`, }, { id: 98, - title: "Chaining Optionals", - level: "basic", + title: 'Chaining Optionals', + level: 'basic', content: - "When accessing nested optional properties, you can use optional chaining " + - "to avoid errors. Learn to handle undefined at depth.", - task: "Access deep properties with safety.", + 'When accessing nested optional properties, you can use optional chaining ' + + 'to avoid errors. Learn to handle undefined at depth.', + task: 'Access deep properties with safety.', hint: 'user?.address?.city ?? "unknown"', starterCode: `interface User { name: string @@ -3837,13 +3838,13 @@ console.log("getCity:", getCity(user1), getCity(user2))`, }, { id: 99, - title: "Type-safe Event-Driven Architecture", - level: "advanced", + title: 'Type-safe Event-Driven Architecture', + level: 'advanced', content: - "Create an event system where emitters and listeners are type-safe. " + - "The event type determines the available data.", - task: "Implement subscribe/publish with derived types.", - hint: "Use generic to relate event and data.", + 'Create an event system where emitters and listeners are type-safe. ' + + 'The event type determines the available data.', + task: 'Implement subscribe/publish with derived types.', + hint: 'Use generic to relate event and data.', starterCode: `type EventMap = { userCreated: { id: number; email: string } userUpdated: { id: number; changes: Record } @@ -3891,14 +3892,14 @@ emitter.emit("userUpdated", { id: 1, changes: { name: "Alice", age: 26 } })`, }, { id: 100, - title: "Conclusion: Next Steps", - level: "basic", + title: 'Conclusion: Next Steps', + level: 'basic', content: - "Congratulations on completing 100 TypeScript lessons! You now have a solid foundation. " + - "Next steps: contribute to open source projects, explore libraries like React/Next.js, " + - "and practice with coding challenges.", + 'Congratulations on completing 100 TypeScript lessons! You now have a solid foundation. ' + + 'Next steps: contribute to open source projects, explore libraries like React/Next.js, ' + + 'and practice with coding challenges.', task: "Review what you've learned and keep practicing!", - hint: "Practice leads to mastery!", + hint: 'Practice leads to mastery!', starterCode: `console.log("🎉 Congratulations!") console.log("") console.log("You completed 100 TypeScript lessons!") @@ -3926,13 +3927,13 @@ console.log("Good journey! 🚀")`, }, { id: 101, - title: "typeof with Objects", - level: "medium", + title: 'typeof with Objects', + level: 'medium', content: - "Use `typeof` to get the type of a variable or object. " + - "This automatically creates a type based on the value.", - task: "Get the type of an object using typeof.", - hint: "type T = typeof myObject", + 'Use `typeof` to get the type of a variable or object. ' + + 'This automatically creates a type based on the value.', + task: 'Get the type of an object using typeof.', + hint: 'type T = typeof myObject', starterCode: `const user = { name: "Alice", age: 25, @@ -3951,12 +3952,13 @@ console.log("New user:", newUser)`, }, { id: 102, - title: "&& and || Operators", - level: "medium", + title: '&& and || Operators', + level: 'medium', content: - "Logical operators work like in JavaScript. " + "Learn to use them with conditional types.", - task: "Use logical operators in expressions.", - hint: "const result = a && b || c", + 'Logical operators work like in JavaScript. ' + + 'Learn to use them with conditional types.', + task: 'Use logical operators in expressions.', + hint: 'const result = a && b || c', starterCode: `const a = true const b = false const c = true @@ -3975,13 +3977,13 @@ console.log("OR result:", orResult)`, }, { id: 103, - title: "Ternary Operator", - level: "medium", + title: 'Ternary Operator', + level: 'medium', content: - "The ternary operator `condition ? value1 : value2` is useful for simple conditions. " + - "It can also be used in types with conditional types.", - task: "Use the ternary operator to choose values.", - hint: "const result = condition ? value1 : value2", + 'The ternary operator `condition ? value1 : value2` is useful for simple conditions. ' + + 'It can also be used in types with conditional types.', + task: 'Use the ternary operator to choose values.', + hint: 'const result = condition ? value1 : value2', starterCode: `const age = 18 const status = age >= 18 ? "adult" : "minor" console.log("Status:", status) @@ -3999,13 +4001,13 @@ console.log(hasItems)`, }, { id: 104, - title: "Arrow Functions", - level: "medium", + title: 'Arrow Functions', + level: 'medium', content: - "Arrow functions are more concise anonymous functions. " + - "TypeScript infers parameter and return types.", - task: "Create typed arrow functions.", - hint: "const fn = (x: number): number => x * 2", + 'Arrow functions are more concise anonymous functions. ' + + 'TypeScript infers parameter and return types.', + task: 'Create typed arrow functions.', + hint: 'const fn = (x: number): number => x * 2', starterCode: `const add = (a: number, b: number): number => a + b const greet = (name: string): string => \`Hello, \${name}!\` const double = (x: number) => x * 2 @@ -4023,13 +4025,13 @@ console.log(process(numbers, double))`, }, { id: 105, - title: "Spread in Objects", - level: "medium", + title: 'Spread in Objects', + level: 'medium', content: - "The spread operator `...` copies properties from objects. " + - "Useful for creating copies and merging objects.", - task: "Use spread to merge objects.", - hint: "const merged = { ...obj1, ...obj2 }", + 'The spread operator `...` copies properties from objects. ' + + 'Useful for creating copies and merging objects.', + task: 'Use spread to merge objects.', + hint: 'const merged = { ...obj1, ...obj2 }', starterCode: `const defaults = { theme: "dark", language: "pt-BR" } const userPrefs = { theme: "light" } @@ -4047,13 +4049,13 @@ console.log("Full:", full)`, }, { id: 106, - title: "Spread in Arrays", - level: "medium", + title: 'Spread in Arrays', + level: 'medium', content: - "Spread in arrays creates new copies or concatenates arrays. " + - "Does not modify the original array (immutability).", - task: "Use spread to manipulate arrays.", - hint: "const combined = [...arr1, ...arr2]", + 'Spread in arrays creates new copies or concatenates arrays. ' + + 'Does not modify the original array (immutability).', + task: 'Use spread to manipulate arrays.', + hint: 'const combined = [...arr1, ...arr2]', starterCode: `const arr1 = [1, 2, 3] const arr2 = [4, 5, 6] @@ -4072,13 +4074,13 @@ console.log("Doubled:", updated)`, }, { id: 107, - title: "Object Destructuring", - level: "medium", + title: 'Object Destructuring', + level: 'medium', content: - "Destructuring extracts properties from objects into variables. " + - "Can use default values for optional properties.", - task: "Extract properties from an object.", - hint: "const { name, age } = user", + 'Destructuring extracts properties from objects into variables. ' + + 'Can use default values for optional properties.', + task: 'Extract properties from an object.', + hint: 'const { name, age } = user', starterCode: `const user = { name: "Alice", age: 25, @@ -4099,13 +4101,13 @@ console.log(greet(user))`, }, { id: 108, - title: "Array Destructuring", - level: "medium", + title: 'Array Destructuring', + level: 'medium', content: - "Array destructuring uses position, not names. " + - "Can ignore elements or use rest parameters.", - task: "Extract elements from an array by position.", - hint: "const [first, second] = arr", + 'Array destructuring uses position, not names. ' + + 'Can ignore elements or use rest parameters.', + task: 'Extract elements from an array by position.', + hint: 'const [first, second] = arr', starterCode: `const coords = [10, 20, 30] const [x, y, z] = coords console.log("Coords:", x, y, z) @@ -4125,13 +4127,13 @@ console.log("Sum:", sum([5, 3]))`, }, { id: 109, - title: "Array Methods - map", - level: "medium", + title: 'Array Methods - map', + level: 'medium', content: - "map creates a new array transforming each element. " + - "TypeScript infers the type of the resulting array.", - task: "Use map to transform an array.", - hint: "const doubled = nums.map(n => n * 2)", + 'map creates a new array transforming each element. ' + + 'TypeScript infers the type of the resulting array.', + task: 'Use map to transform an array.', + hint: 'const doubled = nums.map(n => n * 2)', starterCode: `const numbers = [1, 2, 3, 4, 5] const doubled = numbers.map(n => n * 2) @@ -4162,13 +4164,13 @@ console.log("Birthdays:", birthdays)`, }, { id: 110, - title: "Array Methods - filter", - level: "medium", + title: 'Array Methods - filter', + level: 'medium', content: - "filter creates a new array with elements that pass the test. " + - "TypeScript automatically refines the type.", - task: "Filter an array using filter.", - hint: "const evens = nums.filter(n => n % 2 === 0)", + 'filter creates a new array with elements that pass the test. ' + + 'TypeScript automatically refines the type.', + task: 'Filter an array using filter.', + hint: 'const evens = nums.filter(n => n % 2 === 0)', starterCode: `const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] const evens = numbers.filter(n => n % 2 === 0) @@ -4200,11 +4202,13 @@ console.log("Under 1000:", affordable)`, }, { id: 111, - title: "Array Methods - reduce", - level: "medium", - content: "reduce reduces an array to a single value. " + "The accumulator can be any type.", - task: "Sum all numbers in an array.", - hint: "const sum = arr.reduce((acc, n) => acc + n, 0)", + title: 'Array Methods - reduce', + level: 'medium', + content: + 'reduce reduces an array to a single value. ' + + 'The accumulator can be any type.', + task: 'Sum all numbers in an array.', + hint: 'const sum = arr.reduce((acc, n) => acc + n, 0)', starterCode: `const numbers = [1, 2, 3, 4, 5] const sum = numbers.reduce((acc, n) => acc + n, 0) @@ -4238,13 +4242,13 @@ console.log("By age:", byAge)`, }, { id: 112, - title: "Array Methods - find and findIndex", - level: "medium", + title: 'Array Methods - find and findIndex', + level: 'medium', content: - "find returns the first element that satisfies the condition. " + - "findIndex returns its position.", - task: "Find an element in the array.", - hint: "const found = arr.find(x => x.id === 1)", + 'find returns the first element that satisfies the condition. ' + + 'findIndex returns its position.', + task: 'Find an element in the array.', + hint: 'const found = arr.find(x => x.id === 1)', starterCode: `const numbers = [10, 20, 30, 40, 50] const found = numbers.find(n => n > 25) @@ -4272,12 +4276,13 @@ console.log("Index:", userIndex)`, }, { id: 113, - title: "Array Methods - some and every", - level: "medium", + title: 'Array Methods - some and every', + level: 'medium', content: - "some returns true if any element passes the test. " + "every returns true if all pass.", - task: "Check conditions in arrays.", - hint: "const hasEvens = arr.some(n => n % 2 === 0)", + 'some returns true if any element passes the test. ' + + 'every returns true if all pass.', + task: 'Check conditions in arrays.', + hint: 'const hasEvens = arr.some(n => n % 2 === 0)', starterCode: `const numbers = [1, 3, 5, 7, 9] const hasEvens = numbers.some(n => n % 2 === 0) @@ -4308,13 +4313,13 @@ console.log("All available:", allAvailable)`, }, { id: 114, - title: "Array Methods - includes and indexOf", - level: "medium", + title: 'Array Methods - includes and indexOf', + level: 'medium', content: - "includes checks if a value exists in the array. " + - "indexOf returns the position or -1 if not found.", - task: "Check if a value exists in the array.", - hint: "const exists = arr.includes(value)", + 'includes checks if a value exists in the array. ' + + 'indexOf returns the position or -1 if not found.', + task: 'Check if a value exists in the array.', + hint: 'const exists = arr.includes(value)', starterCode: `const fruits = ["apple", "banana", "orange"] console.log("Has banana:", fruits.includes("banana")) @@ -4339,12 +4344,13 @@ console.log("Unique:", unique([1, 2, 2, 3, 3, 3]))`, }, { id: 115, - title: "Array Methods - sort", - level: "medium", + title: 'Array Methods - sort', + level: 'medium', content: - "sort sorts elements in place. " + "For correct sorting, provide a comparator function.", - task: "Sort an array of numbers.", - hint: "const sorted = arr.sort((a, b) => a - b)", + 'sort sorts elements in place. ' + + 'For correct sorting, provide a comparator function.', + task: 'Sort an array of numbers.', + hint: 'const sorted = arr.sort((a, b) => a - b)', starterCode: `const numbers = [5, 2, 8, 1, 9] const ascending = [...numbers].sort((a, b) => a - b) @@ -4372,13 +4378,13 @@ console.log("By age:", byAge.map(u => u.name))`, }, { id: 116, - title: "Array Methods - slice and splice", - level: "medium", + title: 'Array Methods - slice and splice', + level: 'medium', content: - "slice returns a copy of a portion of the array. " + - "splice removes/replaces elements in place.", - task: "Extract and modify arrays.", - hint: "const portion = arr.slice(1, 3)", + 'slice returns a copy of a portion of the array. ' + + 'splice removes/replaces elements in place.', + task: 'Extract and modify arrays.', + hint: 'const portion = arr.slice(1, 3)', starterCode: `const numbers = [0, 1, 2, 3, 4, 5] const portion = numbers.slice(1, 4) @@ -4403,11 +4409,13 @@ console.log("After insert:", arr2)`, }, { id: 117, - title: "Array Methods - flat", - level: "medium", - content: "flat flattens nested arrays. " + "flatMap combines map and flat in one operation.", - task: "Flatten nested arrays.", - hint: "const flat = nested.flat()", + title: 'Array Methods - flat', + level: 'medium', + content: + 'flat flattens nested arrays. ' + + 'flatMap combines map and flat in one operation.', + task: 'Flatten nested arrays.', + hint: 'const flat = nested.flat()', starterCode: `const nested = [1, [2, 3], [4, [5, 6]]] const flat1 = nested.flat() @@ -4429,12 +4437,12 @@ console.log("Doubled + 1:", doubledAndPlusOne)`, }, { id: 118, - title: "String Methods", - level: "medium", + title: 'String Methods', + level: 'medium', content: - "Strings have useful methods like split, join, trim, etc. " + - "TypeScript treats them as string methods.", - task: "Manipulate a string.", + 'Strings have useful methods like split, join, trim, etc. ' + + 'TypeScript treats them as string methods.', + task: 'Manipulate a string.', hint: "str.split(',').join('-')", starterCode: `const text = " Hello, World! " @@ -4458,13 +4466,13 @@ console.log("Slice:", email.slice(0, 4))`, }, { id: 119, - title: "Math and Number", - level: "medium", + title: 'Math and Number', + level: 'medium', content: - "Math provides useful mathematical functions. " + - "Number has constants and methods for conversion.", - task: "Use Math and Number for operations.", - hint: "Math.floor(Math.random() * 10)", + 'Math provides useful mathematical functions. ' + + 'Number has constants and methods for conversion.', + task: 'Use Math and Number for operations.', + hint: 'Math.floor(Math.random() * 10)', starterCode: `console.log("Round:", Math.round(4.5)) console.log("Floor:", Math.floor(4.9)) console.log("Ceil:", Math.ceil(4.1)) @@ -4485,11 +4493,13 @@ console.log("IsFinite:", Number.isFinite(Infinity))`, }, { id: 120, - title: "Date", - level: "medium", - content: "Date represents dates and times. " + "Methods get individual components.", - task: "Work with dates.", - hint: "const now = new Date()", + title: 'Date', + level: 'medium', + content: + 'Date represents dates and times. ' + + 'Methods get individual components.', + task: 'Work with dates.', + hint: 'const now = new Date()', starterCode: `const now = new Date() console.log("Now:", now) console.log("ISO:", now.toISOString()) @@ -4510,12 +4520,13 @@ console.log("After week:", afterWeek.toDateString())`, }, { id: 121, - title: "JSON parse and stringify", - level: "medium", + title: 'JSON parse and stringify', + level: 'medium', content: - "JSON.stringify converts objects to string. " + "JSON.parse converts string to object.", - task: "Serialize and deserialize JSON.", - hint: "JSON.parse(jsonString)", + 'JSON.stringify converts objects to string. ' + + 'JSON.parse converts string to object.', + task: 'Serialize and deserialize JSON.', + hint: 'JSON.parse(jsonString)', starterCode: `const obj = { name: "Alice", age: 25, @@ -4537,13 +4548,13 @@ console.log("User:", user.name)`, }, { id: 122, - title: "Promise.all and Promise.race", - level: "medium", + title: 'Promise.all and Promise.race', + level: 'medium', content: - "Promise.all waits for all promises to resolve. " + - "Promise.race returns the first one to resolve.", - task: "Work with multiple promises.", - hint: "Promise.all([p1, p2])", + 'Promise.all waits for all promises to resolve. ' + + 'Promise.race returns the first one to resolve.', + task: 'Work with multiple promises.', + hint: 'Promise.all([p1, p2])', starterCode: `const p1 = Promise.resolve(1) const p2 = Promise.resolve(2) const p3 = Promise.resolve(3) @@ -4568,13 +4579,13 @@ Promise.allSettled([fail, success]).then(results => { }, { id: 123, - title: "try/catch/finally", - level: "medium", + title: 'try/catch/finally', + level: 'medium', content: - "try executes code, catch handles errors, finally always executes. " + - "TypeScript infers the error type as unknown.", - task: "Handle errors with try/catch.", - hint: "try { } catch (e) { }", + 'try executes code, catch handles errors, finally always executes. ' + + 'TypeScript infers the error type as unknown.', + task: 'Handle errors with try/catch.', + hint: 'try { } catch (e) { }', starterCode: `function divide(a: number, b: number): number { if (b === 0) throw new Error("Division by zero") return a / b @@ -4602,10 +4613,11 @@ console.log(safeParse("invalid"))`, }, { id: 124, - title: "throw and Error", - level: "medium", - content: "throw throws exceptions. " + "The Error type has message and name.", - task: "Throw custom errors.", + title: 'throw and Error', + level: 'medium', + content: + 'throw throws exceptions. ' + 'The Error type has message and name.', + task: 'Throw custom errors.', hint: "throw new Error('message')", starterCode: `function validateAge(age: number): void { if (age < 0) { @@ -4637,11 +4649,13 @@ try { }, { id: 125, - title: "setTimeout and setInterval", - level: "medium", - content: "setTimeout executes after a delay. " + "setInterval executes repeatedly.", - task: "Schedule code execution.", - hint: "setTimeout(() => {}, 1000)", + title: 'setTimeout and setInterval', + level: 'medium', + content: + 'setTimeout executes after a delay. ' + + 'setInterval executes repeatedly.', + task: 'Schedule code execution.', + hint: 'setTimeout(() => {}, 1000)', starterCode: `console.log("Before timeout") setTimeout(() => { @@ -4662,11 +4676,13 @@ const interval = setInterval(() => { }, { id: 126, - title: "clearTimeout and clearInterval", - level: "medium", - content: "clearTimeout cancels a setTimeout. " + "clearInterval stops a setInterval.", - task: "Cancel timers.", - hint: "clearTimeout(timerId)", + title: 'clearTimeout and clearInterval', + level: 'medium', + content: + 'clearTimeout cancels a setTimeout. ' + + 'clearInterval stops a setInterval.', + task: 'Cancel timers.', + hint: 'clearTimeout(timerId)', starterCode: `const timeoutId = setTimeout(() => { console.log("This won't print") }, 1000) @@ -4687,12 +4703,13 @@ const intervalId = setInterval(() => { }, { id: 127, - title: "Object.keys, values, entries", - level: "medium", + title: 'Object.keys, values, entries', + level: 'medium', content: - "Object.keys returns keys, values returns values, " + "entries returns [key, value] pairs.", - task: "Iterate over object properties.", - hint: "Object.keys(obj)", + 'Object.keys returns keys, values returns values, ' + + 'entries returns [key, value] pairs.', + task: 'Iterate over object properties.', + hint: 'Object.keys(obj)', starterCode: `const user = { name: "Alice", age: 25, @@ -4713,13 +4730,13 @@ Object.entries(user).forEach(([key, value]) => { }, { id: 128, - title: "Object.assign", - level: "medium", + title: 'Object.assign', + level: 'medium', content: - "Object.assign copies properties from source objects to a destination. " + - "Similar to the spread operator.", - task: "Copy properties between objects.", - hint: "Object.assign(target, source)", + 'Object.assign copies properties from source objects to a destination. ' + + 'Similar to the spread operator.', + task: 'Copy properties between objects.', + hint: 'Object.assign(target, source)', starterCode: `const target = { a: 1 } const source = { b: 2, c: 3 } @@ -4738,13 +4755,13 @@ console.log("Clone:", clone)`, }, { id: 129, - title: "Object.freeze and seal", - level: "medium", + title: 'Object.freeze and seal', + level: 'medium', content: - "Object.freeze prevents adding/modifying properties. " + - "Object.seal prevents adding but allows modification.", - task: "Make an object immutable.", - hint: "Object.freeze(obj)", + 'Object.freeze prevents adding/modifying properties. ' + + 'Object.seal prevents adding but allows modification.', + task: 'Make an object immutable.', + hint: 'Object.freeze(obj)', starterCode: `const obj = { name: "Alice", age: 25 } Object.freeze(obj) @@ -4770,11 +4787,13 @@ console.log("Sealed new prop:", sealed.newProp)`, }, { id: 130, - title: "Array.isArray", - level: "medium", - content: "Array.isArray checks if a value is an array. " + "Useful for type guards.", - task: "Check if something is an array.", - hint: "Array.isArray(value)", + title: 'Array.isArray', + level: 'medium', + content: + 'Array.isArray checks if a value is an array. ' + + 'Useful for type guards.', + task: 'Check if something is an array.', + hint: 'Array.isArray(value)', starterCode: `console.log("Is array:", Array.isArray([1, 2, 3])) console.log("Not array:", Array.isArray("hello")) console.log("Not array:", Array.isArray({ length: 3 })) @@ -4794,13 +4813,13 @@ process({ 0: "a", 1: "b", length: 2 })`, }, { id: 131, - title: "Boolean Coercion", - level: "medium", + title: 'Boolean Coercion', + level: 'medium', content: - "Values can be converted to boolean with !! or Boolean(). " + + 'Values can be converted to boolean with !! or Boolean(). ' + 'Understand falsy values: false, 0, "", null, undefined, NaN.', - task: "Convert values to boolean.", - hint: "const bool = !!value", + task: 'Convert values to boolean.', + hint: 'const bool = !!value', starterCode: `console.log("Boolean of 1:", Boolean(1)) console.log("Boolean of 0:", Boolean(0)) console.log("Boolean of '':", Boolean("")) @@ -4819,12 +4838,12 @@ console.log("Bool:", bool)`, }, { id: 132, - title: "Number Coercion", - level: "medium", + title: 'Number Coercion', + level: 'medium', content: - "Convert strings to numbers with Number(), parseInt(), parseFloat(). " + - "Understand the difference between them.", - task: "Convert strings to numbers.", + 'Convert strings to numbers with Number(), parseInt(), parseFloat(). ' + + 'Understand the difference between them.', + task: 'Convert strings to numbers.', hint: "Number('42') or parseInt('42')", starterCode: `console.log("Number('42'):", Number("42")) console.log("Number('3.14'):", Number("3.14")) @@ -4844,12 +4863,12 @@ console.log("+ '3.14':", +"3.14")`, }, { id: 133, - title: "String Coercion", - level: "medium", + title: 'String Coercion', + level: 'medium', content: - "Convert values to string with String() or toString(). " + - "Template literals also convert automatically.", - task: "Convert values to string.", + 'Convert values to string with String() or toString(). ' + + 'Template literals also convert automatically.', + task: 'Convert values to string.', hint: "String(42) or 42 + ''", starterCode: `console.log("String(42):", String(42)) console.log("String(true):", String(true)) @@ -4869,13 +4888,13 @@ console.log("\`Bool: \${bool}\`:", \`Bool: \${bool}\`)`, }, { id: 134, - title: "Default Parameters", - level: "medium", + title: 'Default Parameters', + level: 'medium', content: - "Parameters with default values are used when the argument is undefined. " + - "Different from optional (?), which can be omitted completely.", - task: "Use parameters with default values.", - hint: "function fn(a: number = 10)", + 'Parameters with default values are used when the argument is undefined. ' + + 'Different from optional (?), which can be omitted completely.', + task: 'Use parameters with default values.', + hint: 'function fn(a: number = 10)', starterCode: `function greet(name: string = "World"): string { return \`Hello, \${name}!\` } @@ -4899,13 +4918,13 @@ console.log(createUser("Charlie", 25))`, }, { id: 135, - title: "Rest Parameters", - level: "medium", + title: 'Rest Parameters', + level: 'medium', content: - "Rest parameters collect multiple arguments into an array. " + - "Useful for functions with variable number of parameters.", - task: "Create a function with rest parameters.", - hint: "function fn(...args: number[])", + 'Rest parameters collect multiple arguments into an array. ' + + 'Useful for functions with variable number of parameters.', + task: 'Create a function with rest parameters.', + hint: 'function fn(...args: number[])', starterCode: `function sum(...numbers: number[]): number { return numbers.reduce((a, b) => a + b, 0) } @@ -4925,13 +4944,13 @@ console.log("Spread:", sum(...arr))`, }, { id: 136, - title: "Arguments Object", - level: "medium", + title: 'Arguments Object', + level: 'medium', content: - "arguments is an array-like object available in regular functions. " + + 'arguments is an array-like object available in regular functions. ' + "Arrow functions don't have arguments.", - task: "Access arguments via arguments.", - hint: "function fn() { console.log(arguments) }", + task: 'Access arguments via arguments.', + hint: 'function fn() { console.log(arguments) }', starterCode: `function sum(): number { let total = 0 for (let i = 0; i < arguments.length; i++) { @@ -4951,12 +4970,13 @@ showArgs(1, "hello", true)`, }, { id: 137, - title: "IIFE - Immediately Invoked Function", - level: "medium", + title: 'IIFE - Immediately Invoked Function', + level: 'medium', content: - "IIFE is a function that executes immediately. " + "Useful for creating private scope.", - task: "Create an IIFE.", - hint: "(() => { })()", + 'IIFE is a function that executes immediately. ' + + 'Useful for creating private scope.', + task: 'Create an IIFE.', + hint: '(() => { })()', starterCode: `(function() { const privateVar = "I'm private" console.log("IIFE executed:", privateVar) @@ -4984,13 +5004,13 @@ console.log("Counter:", counter.get())`, }, { id: 138, - title: "Callback Functions", - level: "medium", + title: 'Callback Functions', + level: 'medium', content: - "Callbacks are functions passed as arguments to other functions. " + - "Commonly used in event listeners and array methods.", - task: "Pass a function as a callback.", - hint: "arr.forEach((item) => { })", + 'Callbacks are functions passed as arguments to other functions. ' + + 'Commonly used in event listeners and array methods.', + task: 'Pass a function as a callback.', + hint: 'arr.forEach((item) => { })', starterCode: `function processArray( arr: number[], callback: (n: number) => number @@ -5024,11 +5044,13 @@ withCallback("Alice", (err, result) => { }, { id: 139, - title: "for...in and for...of", - level: "medium", - content: "for...in iterates over object keys. " + "for...of iterates over values of iterables.", - task: "Iterate over objects and arrays.", - hint: "for...of for arrays", + title: 'for...in and for...of', + level: 'medium', + content: + 'for...in iterates over object keys. ' + + 'for...of iterates over values of iterables.', + task: 'Iterate over objects and arrays.', + hint: 'for...of for arrays', starterCode: `const user = { name: "Alice", age: 25, city: "SP" } console.log("for...in:") @@ -5050,11 +5072,13 @@ for (const [index, num] of numbers.entries()) { }, { id: 140, - title: "while and do...while", - level: "medium", - content: "while executes while the condition is true. " + "do...while executes at least once.", - task: "Use while loops.", - hint: "while (condition) { }", + title: 'while and do...while', + level: 'medium', + content: + 'while executes while the condition is true. ' + + 'do...while executes at least once.', + task: 'Use while loops.', + hint: 'while (condition) { }', starterCode: `let count = 0 while (count < 5) { @@ -5084,11 +5108,13 @@ console.log("Length:", chars)`, }, { id: 141, - title: "break and continue", - level: "medium", - content: "break exits the loop completely. " + "continue skips to the next iteration.", - task: "Control loop flow.", - hint: "break to exit, continue to skip", + title: 'break and continue', + level: 'medium', + content: + 'break exits the loop completely. ' + + 'continue skips to the next iteration.', + task: 'Control loop flow.', + hint: 'break to exit, continue to skip', starterCode: `for (let i = 1; i <= 10; i++) { if (i === 5) break console.log("i:", i) @@ -5114,11 +5140,12 @@ console.log("Found:", found)`, }, { id: 142, - title: "Labeled Statements", - level: "medium", - content: "Labels identify loops for break/continue. " + "Useful for nested loops.", - task: "Use labels to control nested loops.", - hint: "label: for (...)", + title: 'Labeled Statements', + level: 'medium', + content: + 'Labels identify loops for break/continue. ' + 'Useful for nested loops.', + task: 'Use labels to control nested loops.', + hint: 'label: for (...)', starterCode: `outer: for (let i = 1; i <= 3; i++) { for (let j = 1; j <= 3; j++) { console.log(\`i=\${i}, j=\${j}\`) @@ -5142,10 +5169,12 @@ outer2: while (i < 3) { }, { id: 143, - title: "typeof operator", - level: "medium", - content: "typeof returns the type of a value as a string. " + "Useful for basic type guards.", - task: "Use typeof to check types.", + title: 'typeof operator', + level: 'medium', + content: + 'typeof returns the type of a value as a string. ' + + 'Useful for basic type guards.', + task: 'Use typeof to check types.', hint: "typeof value === 'string'", starterCode: `console.log("typeof 'hello':", typeof "hello") console.log("typeof 42:", typeof 42) @@ -5168,13 +5197,13 @@ console.log(process(42))`, }, { id: 144, - title: "instanceof", - level: "medium", + title: 'instanceof', + level: 'medium', content: - "instanceof checks if an object is an instance of a class. " + - "Also works for built-in objects like Array, Date.", - task: "Use instanceof to check classes.", - hint: "value instanceof Array", + 'instanceof checks if an object is an instance of a class. ' + + 'Also works for built-in objects like Array, Date.', + task: 'Use instanceof to check classes.', + hint: 'value instanceof Array', starterCode: `class Dog { bark() { return "Woof!" } } @@ -5205,12 +5234,12 @@ process([1, 2, 3])`, }, { id: 145, - title: "in operator", - level: "medium", + title: 'in operator', + level: 'medium', content: - "in checks if a property exists in an object. " + - "Returns true for own and inherited (use hasOwnProperty for own only).", - task: "Use in to check properties.", + 'in checks if a property exists in an object. ' + + 'Returns true for own and inherited (use hasOwnProperty for own only).', + task: 'Use in to check properties.', hint: "'prop' in object", starterCode: `const user = { name: "Alice", age: 25 } @@ -5239,12 +5268,13 @@ console.log(hasProp(car, "year"))`, }, { id: 146, - title: "delete operator", - level: "medium", + title: 'delete operator', + level: 'medium', content: - "delete removes properties from objects. " + "Does not work on variables or functions.", - task: "Remove properties from objects.", - hint: "delete object.property", + 'delete removes properties from objects. ' + + 'Does not work on variables or functions.', + task: 'Remove properties from objects.', + hint: 'delete object.property', starterCode: `const user = { name: "Alice", age: 25, city: "SP" } console.log("Before delete:", user) @@ -5262,13 +5292,13 @@ console.log("'2' in arr:", "2" in arr)`, }, { id: 147, - title: "void operator", - level: "medium", + title: 'void operator', + level: 'medium', content: - "void evaluates an expression and returns undefined. " + - "Useful for IIFEs or preventing navigation in links.", - task: "Use void operator.", - hint: "void expression", + 'void evaluates an expression and returns undefined. ' + + 'Useful for IIFEs or preventing navigation in links.', + task: 'Use void operator.', + hint: 'void expression', starterCode: `console.log("void 0:", void 0) console.log("void 1+1:", void 1 + 1) @@ -5288,13 +5318,13 @@ console.log("Use void for preventDefault")`, }, { id: 148, - title: "Comma Operator", - level: "medium", + title: 'Comma Operator', + level: 'medium', content: - "The comma evaluates expressions from left to right and returns the last one. " + - "Useful in for loops and compact expressions.", - task: "Use comma operator.", - hint: "(a, b, c) - returns c", + 'The comma evaluates expressions from left to right and returns the last one. ' + + 'Useful in for loops and compact expressions.', + task: 'Use comma operator.', + hint: '(a, b, c) - returns c', starterCode: `const result = (1, 2, 3) console.log("Result:", result) @@ -5312,13 +5342,13 @@ console.log("Coords:", coords)`, }, { id: 149, - title: "Bitwise Operators", - level: "medium", + title: 'Bitwise Operators', + level: 'medium', content: - "Bitwise operators manipulate bits of numbers. " + - "Useful for flags, encryption, optimization.", - task: "Use bitwise operators.", - hint: "& | ^ ~ << >>", + 'Bitwise operators manipulate bits of numbers. ' + + 'Useful for flags, encryption, optimization.', + task: 'Use bitwise operators.', + hint: '& | ^ ~ << >>', starterCode: `console.log("5 & 3:", 5 & 3) console.log("5 | 3:", 5 | 3) console.log("5 ^ 3:", 5 ^ 3) @@ -5345,12 +5375,12 @@ console.log("After removing A:", flags)`, }, { id: 150, - title: "eval", - level: "medium", + title: 'eval', + level: 'medium', content: - "eval executes a string as JavaScript code. " + - "Avoid using in production code for security.", - task: "Use eval carefully.", + 'eval executes a string as JavaScript code. ' + + 'Avoid using in production code for security.', + task: 'Use eval carefully.', hint: "eval('code string')", starterCode: `const code = "2 + 2" console.log("Result:", eval(code)) diff --git a/src/data/lessons/lessons.ts b/src/data/lessons/lessons.ts index 4392db0..393caf0 100644 --- a/src/data/lessons/lessons.ts +++ b/src/data/lessons/lessons.ts @@ -1,18 +1,18 @@ -import type { Lesson } from "./types"; -export type { Level, Lesson } from "./types"; +import type { Lesson } from './types'; +export type { Level, Lesson } from './types'; export const lessons: Lesson[] = [ { id: 1, - title: "Bem-vindo ao TypeScript", - level: "basic", + title: 'Bem-vindo ao TypeScript', + level: 'basic', content: - "TypeScript é um superconjunto de JavaScript que adiciona tipagem estática. " + + 'TypeScript é um superconjunto de JavaScript que adiciona tipagem estática. ' + 'Com ele, você define o "formato" dos seus dados usando interfaces, evitando ' + - "erros em tempo de execução. Veja o exemplo: criamos uma interface `User` com " + - "dois campos tipados e instanciamos um objeto que a respeita.", + 'erros em tempo de execução. Veja o exemplo: criamos uma interface `User` com ' + + 'dois campos tipados e instanciamos um objeto que a respeita.', task: "Altere o nome do usuário de 'TypeScript Explorer' para outro nome qualquer.", - hint: "Mude o valor de `name` dentro do objeto `user`.", + hint: 'Mude o valor de `name` dentro do objeto `user`.', starterCode: `interface User { name: string; id: number; @@ -27,14 +27,14 @@ console.log(\`Olá, \${user.name}! Seu ID é \${user.id}.\`);`, }, { id: 2, - title: "Tipagem Estática e Inferência", - level: "basic", - content: - "TypeScript infere tipos automaticamente em muitos casos. Quando você define uma variável " + - "com um valor inicial, TypeScript deduz seu tipo. Isso é chamado de inferência de tipo e " + - "torna o código mais conciso enquanto mantém a segurança.", - task: "Observe como o TypeScript infere o tipo da variável `message`.", - hint: "O tipo é inferido a partir do valor inicial.", + title: 'Tipagem Estática e Inferência', + level: 'basic', + content: + 'TypeScript infere tipos automaticamente em muitos casos. Quando você define uma variável ' + + 'com um valor inicial, TypeScript deduz seu tipo. Isso é chamado de inferência de tipo e ' + + 'torna o código mais conciso enquanto mantém a segurança.', + task: 'Observe como o TypeScript infere o tipo da variável `message`.', + hint: 'O tipo é inferido a partir do valor inicial.', starterCode: `let message = "Hello, TypeScript!" let count = 42 let isActive = true @@ -50,13 +50,13 @@ console.log(isActive)`, }, { id: 3, - title: "Interfaces", - level: "basic", + title: 'Interfaces', + level: 'basic', content: - "Interfaces definem a estrutura que objetos devem seguir. São fundamentais em TypeScript " + - "para garantir que objetos tenham as propriedades corretas com os tipos certos.", - task: "Adicione uma propriedade `email` à interface `Person` e ao objeto.", - hint: "Adicione `email: string` na interface.", + 'Interfaces definem a estrutura que objetos devem seguir. São fundamentais em TypeScript ' + + 'para garantir que objetos tenham as propriedades corretas com os tipos certos.', + task: 'Adicione uma propriedade `email` à interface `Person` e ao objeto.', + hint: 'Adicione `email: string` na interface.', starterCode: `interface Person { name: string age: number @@ -71,13 +71,13 @@ console.log(\`\${person.name} tem \${person.age} anos\`)`, }, { id: 4, - title: "Enums", - level: "basic", + title: 'Enums', + level: 'basic', content: - "Enums permitem definir um conjunto de constantes nomeadas. São úteis para " + - "representar estados, direções, papéis de usuário, etc. TypeScript suporta " + - "enums numéricos (padrão) e de string.", - task: "Adicione um valor `ADMIN` ao enum `Role` e crie um usuário com esse papel.", + 'Enums permitem definir um conjunto de constantes nomeadas. São úteis para ' + + 'representar estados, direções, papéis de usuário, etc. TypeScript suporta ' + + 'enums numéricos (padrão) e de string.', + task: 'Adicione um valor `ADMIN` ao enum `Role` e crie um usuário com esse papel.', hint: 'Adicione `ADMIN = "ADMIN"` ao enum e use `Role.ADMIN` no objeto.', starterCode: `enum Direction { UP = "UP", @@ -107,14 +107,14 @@ console.log(\`\${player.name} (\${player.role}) está olhando para \${player.fac }, { id: 5, - title: "Type Aliases e Union Types", - level: "basic", - content: - "Type aliases criam nomes para tipos complexos. Union types (`|`) permitem " + - "que uma variável aceite mais de um tipo. Isso é muito mais seguro do que usar " + - "`any` e ainda mantém a flexibilidade.", - task: "Crie um type alias `Result` que seja `string | number | boolean`.", - hint: "type Result = string | number | boolean;", + title: 'Type Aliases e Union Types', + level: 'basic', + content: + 'Type aliases criam nomes para tipos complexos. Union types (`|`) permitem ' + + 'que uma variável aceite mais de um tipo. Isso é muito mais seguro do que usar ' + + '`any` e ainda mantém a flexibilidade.', + task: 'Crie um type alias `Result` que seja `string | number | boolean`.', + hint: 'type Result = string | number | boolean;', starterCode: `type ID = string | number type Status = "active" | "inactive" | "pending" @@ -137,14 +137,14 @@ console.log(getStatusLabel("active"))`, }, { id: 6, - title: "Type Assertions", - level: "basic", + title: 'Type Assertions', + level: 'basic', content: - "Type assertions dizem ao TypeScript para tratar um valor como um tipo específico. " + + 'Type assertions dizem ao TypeScript para tratar um valor como um tipo específico. ' + 'Use `as` ou sintaxe de colchete angular. É como um "cast" em outras linguagens, ' + - "mas não converte o valor em tempo de execução.", - task: "Use type assertion para tratar `input` como `string`.", - hint: "const str = input as string;", + 'mas não converte o valor em tempo de execução.', + task: 'Use type assertion para tratar `input` como `string`.', + hint: 'const str = input as string;', starterCode: `let input: unknown = "hello world" const length1 = (input as string).length @@ -155,15 +155,15 @@ console.log("Length 2:", length2)`, }, { id: 7, - title: "Tipos Básicos", - level: "basic", + title: 'Tipos Básicos', + level: 'basic', content: - "TypeScript suporta todos os tipos primitivos do JavaScript: `string`, `number`, " + - "`boolean`, `null`, `undefined`. Além disso, oferece `symbol`, `bigint` e o " + - "tipo `void` para funções que não retornam nada.", - task: "Crie variáveis dos tipos aprendidos.", + 'TypeScript suporta todos os tipos primitivos do JavaScript: `string`, `number`, ' + + '`boolean`, `null`, `undefined`. Além disso, oferece `symbol`, `bigint` e o ' + + 'tipo `void` para funções que não retornam nada.', + task: 'Crie variáveis dos tipos aprendidos.', hint: 'let name: string = "Alice";', - starterCode: `let name: string = "Alice" + starterCode: `{let name: string = "Alice" let age: number = 25 let isStudent: boolean = true let nothing: null = null @@ -171,16 +171,16 @@ let notDefined: undefined = undefined let id: symbol = Symbol("id") let bigNumber: bigint = 9007199254740991n -console.log(name, age, isStudent)`, +console.log(name, age, isStudent)}`, }, { id: 8, - title: "Arrays e Tuplas", - level: "basic", + title: 'Arrays e Tuplas', + level: 'basic', content: - "Arrays em TypeScript podem ser tipados como `number[]` ou `Array`. " + - "Tuplas são arrays com tamanho fixo e tipos específicos em cada posição: `[string, number]`.", - task: "Crie uma tupla com o nome e idade de uma pessoa.", + 'Arrays em TypeScript podem ser tipados como `number[]` ou `Array`. ' + + 'Tuplas são arrays com tamanho fixo e tipos específicos em cada posição: `[string, number]`.', + task: 'Crie uma tupla com o nome e idade de uma pessoa.', hint: 'let person: [string, number] = ["Alice", 25];', starterCode: `const numbers: number[] = [1, 2, 3, 4, 5] const names: Array = ["Alice", "Bob", "Charlie"] @@ -194,13 +194,13 @@ console.log("Coords:", coords)`, }, { id: 9, - title: "Funções - Tipagem de Parâmetros e Retorno", - level: "basic", + title: 'Funções - Tipagem de Parâmetros e Retorno', + level: 'basic', content: - "Funções em TypeScript podem ter tipos definidos para parâmetros e retorno. " + - "Isso garante que a função seja chamada com os argumentos corretos e retorne o valor esperado.", - task: "Adicione o tipo de retorno `number` à função `soma`.", - hint: "function soma(a: number, b: number): number", + 'Funções em TypeScript podem ter tipos definidos para parâmetros e retorno. ' + + 'Isso garante que a função seja chamada com os argumentos corretos e retorne o valor esperado.', + task: 'Adicione o tipo de retorno `number` à função `soma`.', + hint: 'function soma(a: number, b: number): number', starterCode: `function greet(name: string): string { return \`Olá, \${name}!\` } @@ -217,14 +217,14 @@ console.log(add(10, 20))`, }, { id: 10, - title: "Parâmetros Opcionais e Default", - level: "basic", - content: - "Parâmetros opcionais usam `?` (ex: `name?: string`). Parâmetros com valor padrão " + - "são automaticamente opcionais. A diferença é que `undefined` é passado para opcionais, " + - "enquanto o valor default é usado para parâmetros com默认值.", - task: "Torne o parâmetro `age` opcional na função `introduce`.", - hint: "function introduce(name: string, age?: number)", + title: 'Parâmetros Opcionais e Default', + level: 'basic', + content: + 'Parâmetros opcionais usam `?` (ex: `name?: string`). Parâmetros com valor padrão ' + + 'são automaticamente opcionais. A diferença é que `undefined` é passado para opcionais, ' + + 'enquanto o valor default é usado para parâmetros com默认值.', + task: 'Torne o parâmetro `age` opcional na função `introduce`.', + hint: 'function introduce(name: string, age?: number)', starterCode: `function greet(name: string, greeting?: string): string { return greeting ? \`\${greeting}, \${name}!\` : \`Olá, \${name}!\` } @@ -243,12 +243,12 @@ console.log(introduce("Diana"))`, }, { id: 11, - title: "Utility Types - Partial, Required, Pick, Omit", - level: "advanced", + title: 'Utility Types - Partial, Required, Pick, Omit', + level: 'advanced', content: - "TypeScript inclui utility types embutidos que transformam tipos existentes: " + - "`Partial` torna todos os campos opcionais, `Required` os torna obrigatórios, " + - "`Pick` seleciona campos, `Omit` remove campos.", + 'TypeScript inclui utility types embutidos que transformam tipos existentes: ' + + '`Partial` torna todos os campos opcionais, `Required` os torna obrigatórios, ' + + '`Pick` seleciona campos, `Omit` remove campos.', task: 'Use `Omit` para criar um tipo `PublicUser`.', hint: 'type PublicUser = Omit', starterCode: `interface User { @@ -276,14 +276,14 @@ console.log("Preview:", JSON.stringify(preview))`, }, { id: 12, - title: "Mapped Types", - level: "advanced", - content: - "Mapped types permitem criar novos tipos transformando cada propriedade de um tipo existente. " + - "Usam a sintaxe `{ [K in keyof T]: ... }`. Combinados com `keyof` e modificadores " + - "(`readonly`, `?`), são extremamente poderosos.", - task: "Crie um mapped type `Nullable` que torne todas as propriedades opcionais.", - hint: "type Nullable = { [K in keyof T]?: T[K] | null; }", + title: 'Mapped Types', + level: 'advanced', + content: + 'Mapped types permitem criar novos tipos transformando cada propriedade de um tipo existente. ' + + 'Usam a sintaxe `{ [K in keyof T]: ... }`. Combinados com `keyof` e modificadores ' + + '(`readonly`, `?`), são extremamente poderosos.', + task: 'Crie um mapped type `Nullable` que torne todas as propriedades opcionais.', + hint: 'type Nullable = { [K in keyof T]?: T[K] | null; }', starterCode: `interface Config { host: string port: number @@ -309,14 +309,14 @@ console.log("Partial:", JSON.stringify(partial))`, }, { id: 13, - title: "Conditional Types", - level: "advanced", - content: - "Conditional types seguem a sintaxe `T extends U ? X : Y` — se `T` é atribuível a `U`, " + - "o tipo resultante é `X`, caso contrário `Y`. Com `infer`, você pode extrair tipos " + - "de dentro de outros tipos.", - task: "Crie um conditional type `IsArray` que retorne `true` se T for array.", - hint: "type IsArray = T extends any[] ? true : false", + title: 'Conditional Types', + level: 'advanced', + content: + 'Conditional types seguem a sintaxe `T extends U ? X : Y` — se `T` é atribuível a `U`, ' + + 'o tipo resultante é `X`, caso contrário `Y`. Com `infer`, você pode extrair tipos ' + + 'de dentro de outros tipos.', + task: 'Crie um conditional type `IsArray` que retorne `true` se T for array.', + hint: 'type IsArray = T extends any[] ? true : false', starterCode: `type IsString = T extends string ? "yes" : "no" type A = IsString @@ -340,14 +340,14 @@ console.log("Result:", JSON.stringify(result))`, }, { id: 14, - title: "Decorators", - level: "advanced", - content: - "Decorators são funções especiais que podem ser aplicadas a classes, métodos, " + - "propriedades e parâmetros usando a sintaxe `@decorator`. São amplamente usados " + - "em frameworks como Angular, NestJS e TypeORM.", - task: "Crie um decorator `@readonly` que torne uma propriedade não-editável.", - hint: "Use Object.defineProperty no descriptor.", + title: 'Decorators', + level: 'advanced', + content: + 'Decorators são funções especiais que podem ser aplicadas a classes, métodos, ' + + 'propriedades e parâmetros usando a sintaxe `@decorator`. São amplamente usados ' + + 'em frameworks como Angular, NestJS e TypeORM.', + task: 'Crie um decorator `@readonly` que torne uma propriedade não-editável.', + hint: 'Use Object.defineProperty no descriptor.', starterCode: `function sealed(constructor: Function) { Object.seal(constructor) Object.seal(constructor.prototype) @@ -381,14 +381,14 @@ console.log("Fib(10):", calc.fibonacci(10))`, }, { id: 15, - title: "Generics - Introdução", - level: "basic", - content: - "Generics permitem criar componentes que funcionam com qualquer tipo, mantendo " + - "a segurança de tipos. São representados por `` e permitem criar funções, " + - "classes e interfaces reutilizáveis.", - task: "Crie uma função `identity` que retorne o mesmo valor passado.", - hint: "function identity(value: T): T { return value; }", + title: 'Generics - Introdução', + level: 'basic', + content: + 'Generics permitem criar componentes que funcionam com qualquer tipo, mantendo ' + + 'a segurança de tipos. São representados por `` e permitem criar funções, ' + + 'classes e interfaces reutilizáveis.', + task: 'Crie uma função `identity` que retorne o mesmo valor passado.', + hint: 'function identity(value: T): T { return value; }', starterCode: `function identity(value: T): T { return value } @@ -401,11 +401,11 @@ console.log(str, num, auto)`, }, { id: 16, - title: "Tipos Literais", - level: "basic", + title: 'Tipos Literais', + level: 'basic', content: - "TypeScript permite especificar valores exatos que uma variável pode ter usando tipos literais. " + - "Isso é útil quando você quer restringir um valor a um conjunto específico de strings ou números.", + 'TypeScript permite especificar valores exatos que uma variável pode ter usando tipos literais. ' + + 'Isso é útil quando você quer restringir um valor a um conjunto específico de strings ou números.', task: "Crie uma variável que possa ter apenas os valores 'pending', 'loading' ou 'success'.", hint: "type Status = 'pending' | 'loading' | 'success';", starterCode: `type Status = "pending" | "loading" | "success" @@ -417,13 +417,13 @@ console.log("Status atual:", currentStatus)`, }, { id: 17, - title: "Funções Sobrescritas (Overloads)", - level: "basic", + title: 'Funções Sobrescritas (Overloads)', + level: 'basic', content: - "TypeScript suporta sobrescrita de funções, permitindo que você defina múltiplas assinaturas. " + - "O TypeScript escolhe a assinatura correta com base nos argumentos fornecidos.", - task: "Crie uma função `format` que possa formatar números e datas.", - hint: "Use múltiplas assinaturas antes da implementação.", + 'TypeScript suporta sobrescrita de funções, permitindo que você defina múltiplas assinaturas. ' + + 'O TypeScript escolhe a assinatura correta com base nos argumentos fornecidos.', + task: 'Crie uma função `format` que possa formatar números e datas.', + hint: 'Use múltiplas assinaturas antes da implementação.', starterCode: `function format(value: string): string function format(value: number, decimals?: number): string function format(value: Date): string @@ -446,13 +446,13 @@ console.log(format(new Date()))`, }, { id: 18, - title: "Módulos e Imports/Exports", - level: "basic", + title: 'Módulos e Imports/Exports', + level: 'basic', content: - "TypeScript dá suporte total ao sistema de módulos ES6. Organize seu código em arquivos " + - "separados com importações e exportações explícitas para melhor encapsulamento.", - task: "Crie e exporte uma função de um módulo, e importe-a em outro.", - hint: "Use `export` e `import` no padrão ES6.", + 'TypeScript dá suporte total ao sistema de módulos ES6. Organize seu código em arquivos ' + + 'separados com importações e exportações explícitas para melhor encapsulamento.', + task: 'Crie e exporte uma função de um módulo, e importe-a em outro.', + hint: 'Use `export` e `import` no padrão ES6.', starterCode: `export const capitalize = (str: string): string => { return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase() } @@ -472,13 +472,13 @@ console.log(trim(text))`, }, { id: 19, - title: "Namespaces", - level: "basic", + title: 'Namespaces', + level: 'basic', content: - "Namespaces agrupam código relacionado sem poluir o escopo global. Use `namespace` " + - "para organizar código internamente e `export` para expor membros.", - task: "Crie um namespace `MathUtils` com funções `add` e `multiply`.", - hint: "namespace MathUtils { export function add(...) }", + 'Namespaces agrupam código relacionado sem poluir o escopo global. Use `namespace` ' + + 'para organizar código internamente e `export` para expor membros.', + task: 'Crie um namespace `MathUtils` com funções `add` e `multiply`.', + hint: 'namespace MathUtils { export function add(...) }', starterCode: `namespace MathUtils { export function add(a: number, b: number): number { return a + b @@ -497,13 +497,13 @@ console.log("PI:", MathUtils.PI)`, }, { id: 20, - title: "Iteradores e Geradores", - level: "basic", + title: 'Iteradores e Geradores', + level: 'basic', content: - "TypeScript dá suporte total aos protocolos iteradores e geradores do ES6. " + - "Geradores (`function*`) fornecem uma maneira fácil de criar funções que retornam sequências.", - task: "Crie uma função geradora que produza números de 1 a N.", - hint: "Use function* e yield.", + 'TypeScript dá suporte total aos protocolos iteradores e geradores do ES6. ' + + 'Geradores (`function*`) fornecem uma maneira fácil de criar funções que retornam sequências.', + task: 'Crie uma função geradora que produza números de 1 a N.', + hint: 'Use function* e yield.', starterCode: `function* counter(limit: number) { let count = 1 while (count <= limit) { @@ -522,13 +522,13 @@ console.log("Como array:", nums)`, }, { id: 21, - title: "Inferência de Tipo Avançada", - level: "advanced", + title: 'Inferência de Tipo Avançada', + level: 'advanced', content: - "TypeScript infere tipos automaticamente em muitos contextos. A inferência funciona " + - "em variáveis, parâmetros, retornos e usa análise de fluxo de controle e contextual typing.", - task: "Observe como o TypeScript infere tipos diferentes no mesmo exemplo.", - hint: "O tipo de retorno muda baseado no parâmetro.", + 'TypeScript infere tipos automaticamente em muitos contextos. A inferência funciona ' + + 'em variáveis, parâmetros, retornos e usa análise de fluxo de controle e contextual typing.', + task: 'Observe como o TypeScript infere tipos diferentes no mesmo exemplo.', + hint: 'O tipo de retorno muda baseado no parâmetro.', starterCode: `function processInput(input: string | number) { if (typeof input === "string") { return input.toUpperCase() @@ -548,13 +548,13 @@ console.log("Doubled:", doubled)`, }, { id: 22, - title: "Compatibilidade Estrutural de Tipos", - level: "advanced", + title: 'Compatibilidade Estrutural de Tipos', + level: 'advanced', content: - "TypeScript usa compatibilidade estrutural — dois tipos são compatíveis se têm a mesma estrutura. " + - "Isso é diferente de sistemas nominativos e torna o TypeScript mais flexível.", - task: "Veja como objetos com estruturas compatíveis podem ser usados interchangeably.", - hint: "Se as propriedades batem, o tipo é compatível.", + 'TypeScript usa compatibilidade estrutural — dois tipos são compatíveis se têm a mesma estrutura. ' + + 'Isso é diferente de sistemas nominativos e torna o TypeScript mais flexível.', + task: 'Veja como objetos com estruturas compatíveis podem ser usados interchangeably.', + hint: 'Se as propriedades batem, o tipo é compatível.', starterCode: `interface Point { x: number y: number @@ -579,13 +579,13 @@ console.log("Distance:", distanceFromOrigin(namedPoint))`, }, { id: 23, - title: "Trabalhando com JavaScript", - level: "basic", + title: 'Trabalhando com JavaScript', + level: 'basic', content: - "TypeScript foi projetado para adotar gradualmente JavaScript existente. " + - "Use `@ts-check` ou `checkJs: true` no tsconfig.json para verificar arquivos .js.", - task: "Entenda como TypeScript verifica código JavaScript.", - hint: "Use JSDoc para adicionar tipos em arquivos .js.", + 'TypeScript foi projetado para adotar gradualmente JavaScript existente. ' + + 'Use `@ts-check` ou `checkJs: true` no tsconfig.json para verificar arquivos .js.', + task: 'Entenda como TypeScript verifica código JavaScript.', + hint: 'Use JSDoc para adicionar tipos em arquivos .js.', starterCode: `// Simulando verificação em arquivo .js // Para habilitar: use // @ts-check no topo @@ -611,13 +611,13 @@ console.log("Fatorial de 5:", factorial(5))`, }, { id: 24, - title: "Arquivos de Declaração (.d.ts)", - level: "advanced", + title: 'Arquivos de Declaração (.d.ts)', + level: 'advanced', content: - "Arquivos de declaração (.d.ts) fornecem informações de tipo para bibliotecas JavaScript. " + - "Definições de tipo para bibliotecas populares estão no DefinitelyTyped (@types/*).", - task: "Crie um arquivo de declaração simples para uma função.", - hint: "declare function nome(params): returnType;", + 'Arquivos de declaração (.d.ts) fornecem informações de tipo para bibliotecas JavaScript. ' + + 'Definições de tipo para bibliotecas populares estão no DefinitelyTyped (@types/*).', + task: 'Crie um arquivo de declaração simples para uma função.', + hint: 'declare function nome(params): returnType;', starterCode: `// Simulando um arquivo de declaração declare namespace Utils { @@ -643,12 +643,12 @@ console.log("Instale tipos: npm install @types/lodash")`, }, { id: 25, - title: "Classes - Introdução", - level: "basic", + title: 'Classes - Introdução', + level: 'basic', content: - "Classes em TypeScript funcionam como em JavaScript moderno, mas com tipagem completa. " + - "Você pode definir propriedades, métodos, construtores e modificadores de acesso.", - task: "Adicione um método `sayHello` à classe `Person`.", + 'Classes em TypeScript funcionam como em JavaScript moderno, mas com tipagem completa. ' + + 'Você pode definir propriedades, métodos, construtores e modificadores de acesso.', + task: 'Adicione um método `sayHello` à classe `Person`.', hint: "sayHello() { return 'Olá, ' + this.name; }", starterCode: `class Person { name: string @@ -669,13 +669,13 @@ console.log(person.greet())`, }, { id: 26, - title: "Modificadores de Acesso", - level: "basic", + title: 'Modificadores de Acesso', + level: 'basic', content: - "TypeScript oferece `public`, `private` e `protected` para controlar o acesso a membros. " + - "Também há `readonly` para propriedades que não podem ser alteradas após inicialização.", - task: "Torne a propriedade `balance` privada e adicione um getter.", - hint: "private balance: number; public getBalance()", + 'TypeScript oferece `public`, `private` e `protected` para controlar o acesso a membros. ' + + 'Também há `readonly` para propriedades que não podem ser alteradas após inicialização.', + task: 'Torne a propriedade `balance` privada e adicione um getter.', + hint: 'private balance: number; public getBalance()', starterCode: `class BankAccount { public readonly id: number private balance: number @@ -706,13 +706,13 @@ console.log("New Balance:", account.getBalance())`, }, { id: 27, - title: "Herança de Classes", - level: "basic", + title: 'Herança de Classes', + level: 'basic', content: - "Classes podem herdar de outras usando `extends`. A classe filha tem acesso a " + - "métodos e propriedades públicas/protegidas da classe pai, e pode sobrescrevê-los.", - task: "Crie uma classe `Student` que herde de `Person`.", - hint: "class Student extends Person { }", + 'Classes podem herdar de outras usando `extends`. A classe filha tem acesso a ' + + 'métodos e propriedades públicas/protegidas da classe pai, e pode sobrescrevê-los.', + task: 'Crie uma classe `Student` que herde de `Person`.', + hint: 'class Student extends Person { }', starterCode: `class Person { constructor(public name: string, public age: number) {} @@ -737,13 +737,13 @@ console.log(student.study())`, }, { id: 28, - title: "Classes Abstratas", - level: "basic", + title: 'Classes Abstratas', + level: 'basic', content: - "Classes abstratas não podem ser instanciadas diretamente, servem como base para outras classes. " + - "Podem conter métodos abstratos (sem implementação) que as classes filhas devem implementar.", - task: "Crie uma classe abstrata `Shape` com método abstrato `area`.", - hint: "abstract class Shape { abstract area(): number; }", + 'Classes abstratas não podem ser instanciadas diretamente, servem como base para outras classes. ' + + 'Podem conter métodos abstratos (sem implementação) que as classes filhas devem implementar.', + task: 'Crie uma classe abstrata `Shape` com método abstrato `area`.', + hint: 'abstract class Shape { abstract area(): number; }', starterCode: `abstract class Shape { abstract area(): number abstract perimeter(): number @@ -789,12 +789,12 @@ console.log(circle.describe())`, }, { id: 29, - title: "Getters e Setters", - level: "basic", + title: 'Getters e Setters', + level: 'basic', content: - "Getters e setters permitem controle preciso sobre o acesso a propriedades. " + - "Úteis para validação, computação de valores, ou manter invariantes de classe.", - task: "Crie um getter `fullName` que retorne nome completo.", + 'Getters e setters permitem controle preciso sobre o acesso a propriedades. ' + + 'Úteis para validação, computação de valores, ou manter invariantes de classe.', + task: 'Crie um getter `fullName` que retorne nome completo.', hint: "get fullName(): string { return this.firstName + ' ' + this.lastName; }", starterCode: `class User { private _password: string = "" @@ -828,13 +828,13 @@ console.log("Password:", user.password)`, }, { id: 30, - title: "Static Members", - level: "basic", + title: 'Static Members', + level: 'basic', content: - "Membros estáticos pertencem à classe em si, não às instâncias. " + - "Acessados via `ClassName.property`, são úteis para constantes ou funções utilitárias.", - task: "Adicione um método estático `createDefault` à classe `User`.", - hint: "static createDefault(): User { }", + 'Membros estáticos pertencem à classe em si, não às instâncias. ' + + 'Acessados via `ClassName.property`, são úteis para constantes ou funções utilitárias.', + task: 'Adicione um método estático `createDefault` à classe `User`.', + hint: 'static createDefault(): User { }', starterCode: `class MathHelper { static readonly PI = 3.14159 @@ -854,14 +854,14 @@ console.log("Factorial 5:", MathHelper.factorial(5))`, }, { id: 31, - title: "Utility Types - Record, Partial, Readonly", - level: "advanced", - content: - "`Record` cria um tipo objeto com chaves K e valores V. " + - "`Partial` torna todas as propriedades opcionais. " + - "`Readonly` torna todas as propriedades apenas leitura.", - task: "Crie um tipo `UserRecord` usando Record.", - hint: "type UserRecord = Record", + title: 'Utility Types - Record, Partial, Readonly', + level: 'advanced', + content: + '`Record` cria um tipo objeto com chaves K e valores V. ' + + '`Partial` torna todas as propriedades opcionais. ' + + '`Readonly` torna todas as propriedades apenas leitura.', + task: 'Crie um tipo `UserRecord` usando Record.', + hint: 'type UserRecord = Record', starterCode: `interface User { id: number name: string @@ -885,13 +885,13 @@ console.log("Partial:", JSON.stringify(partial))`, }, { id: 32, - title: "Utility Types - Extract e Exclude", - level: "advanced", + title: 'Utility Types - Extract e Exclude', + level: 'advanced', content: - "`Extract` extrai de T os tipos que são atribuíveis a U. " + - "`Exclude` remove de T os tipos que são atribuíveis a U.", - task: "Use Extract para obter apenas strings de um union type.", - hint: "type Strings = Extract", + '`Extract` extrai de T os tipos que são atribuíveis a U. ' + + '`Exclude` remove de T os tipos que são atribuíveis a U.', + task: 'Use Extract para obter apenas strings de um union type.', + hint: 'type Strings = Extract', starterCode: `type T = string | number | boolean | null type Strings = Extract @@ -908,13 +908,13 @@ console.log("NotNull:", bool)`, }, { id: 33, - title: "Utility Types - ReturnType e Parameters", - level: "advanced", + title: 'Utility Types - ReturnType e Parameters', + level: 'advanced', content: - "`ReturnType` obtém o tipo de retorno de uma função. " + - "`Parameters` obtém os tipos dos parâmetros como tupla.", - task: "Obtenha o tipo de retorno e parâmetros de uma função.", - hint: "type R = ReturnType", + '`ReturnType` obtém o tipo de retorno de uma função. ' + + '`Parameters` obtém os tipos dos parâmetros como tupla.', + task: 'Obtenha o tipo de retorno e parâmetros de uma função.', + hint: 'type R = ReturnType', starterCode: `function createUser(name: string, age: number): { name: string; age: number; id: number } { return { name, age, id: Math.random() } } @@ -930,13 +930,13 @@ console.log("Args:", args)`, }, { id: 34, - title: "Type Guards", - level: "basic", + title: 'Type Guards', + level: 'basic', content: - "Type guards são expressões que refinam o tipo de uma variável. " + - "Use `typeof`, `instanceof`, ou personalizados com `is` para filtrar tipos em unions.", - task: "Crie um type guard para verificar se um valor é string.", - hint: "function isString(value: unknown): value is string { }", + 'Type guards são expressões que refinam o tipo de uma variável. ' + + 'Use `typeof`, `instanceof`, ou personalizados com `is` para filtrar tipos em unions.', + task: 'Crie um type guard para verificar se um valor é string.', + hint: 'function isString(value: unknown): value is string { }', starterCode: `function isString(value: unknown): value is string { return typeof value === "string" } @@ -970,13 +970,13 @@ if (isDog(pet)) { }, { id: 35, - title: "unknown e any", - level: "basic", + title: 'unknown e any', + level: 'basic', content: - "`any` desabilita a verificação de tipos completamente. " + + '`any` desabilita a verificação de tipos completamente. ' + '`unknown` é o tipo "seguro" que representa qualquer valor — você deve refiná-lo antes de usar.', - task: "Refine um tipo `unknown` para usá-lo com segurança.", - hint: "Use type guards para verificar o tipo.", + task: 'Refine um tipo `unknown` para usá-lo com segurança.', + hint: 'Use type guards para verificar o tipo.', starterCode: `let anyValue: any = "hello" let unknownValue: unknown = "world" @@ -993,13 +993,13 @@ console.log(str)`, }, { id: 36, - title: "never", - level: "basic", + title: 'never', + level: 'basic', content: - "`never` representa valores que nunca ocorrem. Funções que sempre lançam erros " + - "ou loops infinitos têm tipo de retorno `never`. Também é usado em unions exaustivas.", - task: "Crie uma função que lança erro e tem retorno never.", - hint: "function error(): never { throw new Error(); }", + '`never` representa valores que nunca ocorrem. Funções que sempre lançam erros ' + + 'ou loops infinitos têm tipo de retorno `never`. Também é usado em unions exaustivas.', + task: 'Crie uma função que lança erro e tem retorno never.', + hint: 'function error(): never { throw new Error(); }', starterCode: `function throwError(message: string): never { throw new Error(message) } @@ -1030,11 +1030,11 @@ console.log(getDirection("North"))`, }, { id: 37, - title: "keyof e Index Access Types", - level: "advanced", + title: 'keyof e Index Access Types', + level: 'advanced', content: - "`keyof` obtém as chaves de um tipo como union. " + - "Use `T[K]` para acessar o tipo de uma propriedade específica.", + '`keyof` obtém as chaves de um tipo como union. ' + + 'Use `T[K]` para acessar o tipo de uma propriedade específica.', task: "Obtenha as chaves de User e o tipo da propriedade 'name'.", hint: 'type Keys = keyof User; type NameType = User["name"]', starterCode: `interface User { @@ -1059,13 +1059,13 @@ console.log(getProperty(user, "email"))`, }, { id: 38, - title: "Generic Constraints", - level: "basic", + title: 'Generic Constraints', + level: 'basic', content: - "Constraints (restrições) usam `extends` para limitar os tipos que podem ser usados com generics. " + - "Isso garante que o tipo tenha as propriedades necessárias.", - task: "Crie um generic que só aceita objetos com propriedade `length`.", - hint: "function fn(arg: T)", + 'Constraints (restrições) usam `extends` para limitar os tipos que podem ser usados com generics. ' + + 'Isso garante que o tipo tenha as propriedades necessárias.', + task: 'Crie um generic que só aceita objetos com propriedade `length`.', + hint: 'function fn(arg: T)', starterCode: `function getLength(arg: T): number { return arg.length } @@ -1083,13 +1083,13 @@ console.log("Merged:", JSON.stringify(result))`, }, { id: 39, - title: "Generic Classes", - level: "basic", + title: 'Generic Classes', + level: 'basic', content: - "Classes genéricas permitem criar componentes reutilizáveis que funcionam com diferentes tipos. " + - "O tipo é especificado ao criar uma instância da classe.", - task: "Crie uma classe `Box` que armazena um valor.", - hint: "class Box { private content: T; }", + 'Classes genéricas permitem criar componentes reutilizáveis que funcionam com diferentes tipos. ' + + 'O tipo é especificado ao criar uma instância da classe.', + task: 'Crie uma classe `Box` que armazena um valor.', + hint: 'class Box { private content: T; }', starterCode: `class Box { private content: T @@ -1117,13 +1117,13 @@ console.log("Updated:", numberBox.get())`, }, { id: 40, - title: "Generic Interfaces", - level: "basic", + title: 'Generic Interfaces', + level: 'basic', content: - "Interfaces genéricas definem contratos que funcionam com múltiplos tipos. " + - "São a base de bibliotecas como React, Zod e Prisma.", - task: "Crie uma interface `Repository` com métodos CRUD.", - hint: "interface Repository { findAll(): T[]; }", + 'Interfaces genéricas definem contratos que funcionam com múltiplos tipos. ' + + 'São a base de bibliotecas como React, Zod e Prisma.', + task: 'Crie uma interface `Repository` com métodos CRUD.', + hint: 'interface Repository { findAll(): T[]; }', starterCode: `interface Entity { id: number } @@ -1178,13 +1178,13 @@ console.log("Find 1:", repo.findById(1))`, }, { id: 41, - title: "Tipagem de Error Handling", - level: "basic", + title: 'Tipagem de Error Handling', + level: 'basic', content: - "TypeScript melhora o tratamento de erros com melhor inferência em blocos try/catch. " + - "Especifique o tipo do erro para melhor autocomplete.", - task: "Crie uma função que pode lançar erros e trate-os.", - hint: "try { } catch (error) { if (error instanceof Error) { } }", + 'TypeScript melhora o tratamento de erros com melhor inferência em blocos try/catch. ' + + 'Especifique o tipo do erro para melhor autocomplete.', + task: 'Crie uma função que pode lançar erros e trate-os.', + hint: 'try { } catch (error) { if (error instanceof Error) { } }', starterCode: `function divide(a: number, b: number): number { if (b === 0) { throw new Error("Division by zero is not allowed") @@ -1228,13 +1228,13 @@ try { }, { id: 42, - title: "Async/Await e Promises", - level: "basic", + title: 'Async/Await e Promises', + level: 'basic', content: - "TypeScript suporta async/await completamente tipado. Funções async retornam Promises, " + - "e você pode tipar o valor resolvido.", - task: "Crie uma função async que retorna um usuário tipado.", - hint: "async function fetchUser(): Promise { }", + 'TypeScript suporta async/await completamente tipado. Funções async retornam Promises, ' + + 'e você pode tipar o valor resolvido.', + task: 'Crie uma função async que retorna um usuário tipado.', + hint: 'async function fetchUser(): Promise { }', starterCode: `interface User { id: number name: string @@ -1270,13 +1270,13 @@ main()`, }, { id: 43, - title: "this em Tipos", - level: "basic", + title: 'this em Tipos', + level: 'basic', content: - "TypeScript permite tipar `this` em métodos. Use `this` como primeiro parâmetro " + - "para garantir que métodos sejam chamados no contexto correto (fluent API).", - task: "Crie uma fluent API com métodos que retornam `this`.", - hint: "add(name: string): this { }", + 'TypeScript permite tipar `this` em métodos. Use `this` como primeiro parâmetro ' + + 'para garantir que métodos sejam chamados no contexto correto (fluent API).', + task: 'Crie uma fluent API com métodos que retornam `this`.', + hint: 'add(name: string): this { }', starterCode: `class Builder { private parts: string[] = [] @@ -1329,13 +1329,13 @@ console.log("Calc result:", calc.result())`, }, { id: 44, - title: "Optional Chaining e Nullish Coalescing", - level: "basic", + title: 'Optional Chaining e Nullish Coalescing', + level: 'basic', content: - "`?.` acessa propriedades profundas sem erro se algo for null/undefined. " + - "`??` retorna o operando direito se o esquerdo for null/undefined.", - task: "Use optional chaining para acessar propriedade aninhada.", - hint: "user?.address?.city", + '`?.` acessa propriedades profundas sem erro se algo for null/undefined. ' + + '`??` retorna o operando direito se o esquerdo for null/undefined.', + task: 'Use optional chaining para acessar propriedade aninhada.', + hint: 'user?.address?.city', starterCode: `interface User { name: string address?: { @@ -1368,13 +1368,13 @@ console.log("Zero:", zero)`, }, { id: 45, - title: "Non-null Assertion Operator", - level: "basic", + title: 'Non-null Assertion Operator', + level: 'basic', content: - "`!` diz ao TypeScript que um valor não é null/undefined. Use com cautela — " + - "só quando você tem certeza que o valor existe.", - task: "Use non-null assertion para acessar propriedade garantida.", - hint: "element!.value", + '`!` diz ao TypeScript que um valor não é null/undefined. Use com cautela — ' + + 'só quando você tem certeza que o valor existe.', + task: 'Use non-null assertion para acessar propriedade garantida.', + hint: 'element!.value', starterCode: `function getElement(): HTMLInputElement | null { return document.createElement("input") } @@ -1392,13 +1392,13 @@ console.log("Result:", result)`, }, { id: 46, - title: "Type Casting vs Assertion", - level: "basic", + title: 'Type Casting vs Assertion', + level: 'basic', content: - "Type assertions (`as`) convertem tipos. Use-as quando você sabe mais sobre o tipo " + - "do que o TypeScript. Diferente de casting em outras linguagens, não converte o valor.", - task: "Use assertion para converter um tipo para outro.", - hint: "const num = value as number", + 'Type assertions (`as`) convertem tipos. Use-as quando você sabe mais sobre o tipo ' + + 'do que o TypeScript. Diferente de casting em outras linguagens, não converte o valor.', + task: 'Use assertion para converter um tipo para outro.', + hint: 'const num = value as number', starterCode: `let input: unknown = "123" const strLength1 = (input as string).length @@ -1430,13 +1430,13 @@ processAnimal(dog)`, }, { id: 47, - title: "Template Literal Types", - level: "advanced", + title: 'Template Literal Types', + level: 'advanced', content: - "Template literal types criam novos tipos usando strings templates. " + - "Combine com infer para extrair e manipular strings em tipos.", - task: "Crie um tipo que cria getters automaticamente.", - hint: "type Getters = { [K in keyof T as `get${K}`]: () => T[K] }", + 'Template literal types criam novos tipos usando strings templates. ' + + 'Combine com infer para extrair e manipular strings em tipos.', + task: 'Crie um tipo que cria getters automaticamente.', + hint: 'type Getters = { [K in keyof T as `get${K}`]: () => T[K] }', starterCode: `type World = "world" type Greeting = \`hello \${World}\` @@ -1465,12 +1465,12 @@ console.log(getters.getAge())`, }, { id: 48, - title: "Discriminated Unions", - level: "basic", + title: 'Discriminated Unions', + level: 'basic', content: - "Crie unions com uma propriedade em comum (discriminador) para facilitar o TypeScript " + - "identificar qual membro da union está em uso. Muito útil para state management.", - task: "Crie uma discriminated union para formatos de arquivo.", + 'Crie unions com uma propriedade em comum (discriminador) para facilitar o TypeScript ' + + 'identificar qual membro da union está em uso. Muito útil para state management.', + task: 'Crie uma discriminated union para formatos de arquivo.', hint: 'type File = { type: "image", data: ... } | { type: "video", data: ... }', starterCode: `type Loading = { status: "loading" } type Success = { status: "success"; data: string } @@ -1502,13 +1502,13 @@ handleResult(errorResult)`, }, { id: 49, - title: "Mixin Classes", - level: "advanced", + title: 'Mixin Classes', + level: 'advanced', content: - "Mixins são funções que recebem uma classe e retornam uma nova classe com funcionalidades extras. " + - "Útil para composição quando herança simples não é suficiente.", - task: "Crie um mixin `Serializable` que adiciona método toJSON.", - hint: "function Serializable>(Base: T)", + 'Mixins são funções que recebem uma classe e retornam uma nova classe com funcionalidades extras. ' + + 'Útil para composição quando herança simples não é suficiente.', + task: 'Crie um mixin `Serializable` que adiciona método toJSON.', + hint: 'function Serializable>(Base: T)', starterCode: `type Constructor = new (...args: any[]) => T function Serializable>(Base: T) { @@ -1541,13 +1541,13 @@ console.log("User:", JSON.stringify(user, null, 2))`, }, { id: 50, - title: "Declaration Merging", - level: "advanced", + title: 'Declaration Merging', + level: 'advanced', content: 'TypeScript permite que interfaces e namespaces com o mesmo nome sejam "mesclados". ' + - "Interfaces são mescladas automaticamente, namespaces requerem `export`.", - task: "Crie uma interface que é mesclada com outra.", - hint: "interface Animal { name: string; } interface Animal { age: number; }", + 'Interfaces são mescladas automaticamente, namespaces requerem `export`.', + task: 'Crie uma interface que é mesclada com outra.', + hint: 'interface Animal { name: string; } interface Animal { age: number; }', starterCode: `interface User { name: string } @@ -1582,13 +1582,13 @@ console.log("Declaration merging works!")`, }, { id: 51, - title: "Type-safe Event Emitter", - level: "advanced", + title: 'Type-safe Event Emitter', + level: 'advanced', content: - "Crie um emissor de eventos type-safe que garante que listeners e eventos correspondam. " + - "Use generics para mapear nomes de eventos para seus payloads.", - task: "Crie um tipo EventMap e implemente um emitter.", - hint: "type Events = { event: payload }", + 'Crie um emissor de eventos type-safe que garante que listeners e eventos correspondam. ' + + 'Use generics para mapear nomes de eventos para seus payloads.', + task: 'Crie um tipo EventMap e implemente um emitter.', + hint: 'type Events = { event: payload }', starterCode: `type EventMap = { userJoined: { userId: number; name: string } userLeft: { userId: number } @@ -1630,13 +1630,13 @@ emitter.emit("message", { from: "Bob", text: "Hello!" })`, }, { id: 52, - title: "Builder Pattern com Generics", - level: "advanced", + title: 'Builder Pattern com Generics', + level: 'advanced', content: - "O padrão Builder permite construir objetos complexos passo a passo. " + - "Com generics, podemos garantir que os métodos retornem o builder correto.", - task: "Implemente um builder para criar usuários com validation.", - hint: "Use this возврате para method chaining.", + 'O padrão Builder permite construir objetos complexos passo a passo. ' + + 'Com generics, podemos garantir que os métodos retornem o builder correto.', + task: 'Implemente um builder para criar usuários com validation.', + hint: 'Use this возврате para method chaining.', starterCode: `class UserBuilder { private user: { name?: string; age?: number; email?: string } = {} @@ -1676,13 +1676,13 @@ console.log("Built user:", JSON.stringify(user))`, }, { id: 53, - title: "Currying e Function Composition", - level: "basic", + title: 'Currying e Function Composition', + level: 'basic', content: - "Currying transforma funções multi-arg em sequências de funções single-arg. " + - "Composition combina funções para criar pipelines de dados.", - task: "Crie funções curried e as compõe.", - hint: "const add = (a: number) => (b: number) => a + b", + 'Currying transforma funções multi-arg em sequências de funções single-arg. ' + + 'Composition combina funções para criar pipelines de dados.', + task: 'Crie funções curried e as compõe.', + hint: 'const add = (a: number) => (b: number) => a + b', starterCode: `const add = (a: number) => (b: number): number => a + b const multiply = (a: number) => (b: number): number => a * b const subtract = (a: number) => (b: number): number => a - b @@ -1708,13 +1708,13 @@ console.log("pipe(add10, double, subtract5)(5):", processNumber(5))`, }, { id: 54, - title: "Type-safe API Client", - level: "advanced", + title: 'Type-safe API Client', + level: 'advanced', content: - "Crie um cliente HTTP que infere tipos de resposta automaticamente. " + - "Use generics para tipar endpoints e responses.", - task: "Crie um cliente com tipos para GET e POST.", - hint: "class ApiClient { get(url): Promise }", + 'Crie um cliente HTTP que infere tipos de resposta automaticamente. ' + + 'Use generics para tipar endpoints e responses.', + task: 'Crie um cliente com tipos para GET e POST.', + hint: 'class ApiClient { get(url): Promise }', starterCode: `interface User { id: number name: string @@ -1761,13 +1761,13 @@ createUser({ name: "Alice", email: "alice@example.com" }) }, { id: 55, - title: "Flattened Union Types", - level: "advanced", + title: 'Flattened Union Types', + level: 'advanced', content: - "Crie tipos union complexos e use distribuição para transformá-los. " + - "Útil para criar unions de strings literais automaticamente.", - task: "Crie uma union de métodos HTTP a partir de um array.", - hint: "type Method = typeof methods[number]", + 'Crie tipos union complexos e use distribuição para transformá-los. ' + + 'Útil para criar unions de strings literais automaticamente.', + task: 'Crie uma union de métodos HTTP a partir de um array.', + hint: 'type Method = typeof methods[number]', starterCode: `const methods = ["get", "post", "put", "delete", "patch"] as const type HttpMethod = typeof methods[number] @@ -1808,13 +1808,13 @@ console.log("Variants:", variants)`, }, { id: 56, - title: "Immutable Update Patterns", - level: "basic", + title: 'Immutable Update Patterns', + level: 'basic', content: - "Atualize objetos e arrays de forma imutável para evitar mutações acidentais. " + - "Use spread operator e métodos que retornam novos arrays.", - task: "Atualize um objeto aninhado de forma imutável.", - hint: "Use spread para criar novas referências.", + 'Atualize objetos e arrays de forma imutável para evitar mutações acidentais. ' + + 'Use spread operator e métodos que retornam novos arrays.', + task: 'Atualize um objeto aninhado de forma imutável.', + hint: 'Use spread para criar novas referências.', starterCode: `interface State { user: { profile: { @@ -1864,13 +1864,13 @@ console.log("Same reference?", state === newState)`, }, { id: 57, - title: "Recursive Types", - level: "advanced", + title: 'Recursive Types', + level: 'advanced', content: - "Types recursivos permitem representar estruturas hierárquicas como árvores e listas. " + - "Útil para JSON, ASTs, e estruturas de dados aninhadas.", - task: "Crie um tipo para uma árvore de diretórios.", - hint: "interface TreeNode { name: string; children?: TreeNode[] }", + 'Types recursivos permitem representar estruturas hierárquicas como árvores e listas. ' + + 'Útil para JSON, ASTs, e estruturas de dados aninhadas.', + task: 'Crie um tipo para uma árvore de diretórios.', + hint: 'interface TreeNode { name: string; children?: TreeNode[] }', starterCode: `interface TreeNode { name: string type: "file" | "folder" @@ -1920,12 +1920,12 @@ console.log("JSON:", JSON.stringify(json, null, 2))`, }, { id: 58, - title: "Branded Types", - level: "advanced", + title: 'Branded Types', + level: 'advanced', content: 'Branded types adicionam "tags" a tipos existentes para区分 tipos primitivos. ' + - "Útil para IDs, currencies, e valores que precisam de validação semântica.", - task: "Crie branded types para UserId e OrderId.", + 'Útil para IDs, currencies, e valores que precisam de validação semântica.', + task: 'Crie branded types para UserId e OrderId.', hint: 'type UserId = string & { __brand: "UserId" }', starterCode: `type UserId = string & { readonly __brand: "UserId" } type OrderId = string & { readonly __brand: "OrderId" } @@ -1963,12 +1963,12 @@ console.log("Email:", email)`, }, { id: 59, - title: "Finite State Machines", - level: "advanced", + title: 'Finite State Machines', + level: 'advanced', content: - "State machines definem um número finito de estados e transições entre eles. " + - "TypeScript pode garantir que apenas transições válidas ocorram.", - task: "Crie um state machine para um pedido.", + 'State machines definem um número finito de estados e transições entre eles. ' + + 'TypeScript pode garantir que apenas transições válidas ocorram.', + task: 'Crie um state machine para um pedido.', hint: 'type State = "pending" | "shipped" | "delivered"', starterCode: `type OrderState = "pending" | "confirmed" | "shipped" | "delivered" | "cancelled" @@ -2023,12 +2023,12 @@ console.log("After deliver:", order.state)`, }, { id: 60, - title: "Weak Types e Type Gards", - level: "advanced", + title: 'Weak Types e Type Gards', + level: 'advanced', content: - "Weak types são tipos com todas propriedades opcionais. " + - "TypeScript tem verificação especial para garantir que pelo menos uma propriedade seja fornecida.", - task: "Crie uma função que aceita apenas opções válidas.", + 'Weak types são tipos com todas propriedades opcionais. ' + + 'TypeScript tem verificação especial para garantir que pelo menos uma propriedade seja fornecida.', + task: 'Crie uma função que aceita apenas opções válidas.', hint: 'Use "at least one" constraint com keyof', starterCode: `type Options = { timeout?: number @@ -2068,13 +2068,13 @@ console.log(processPoint({ name: "A", x: 10, y: 20 }))`, }, { id: 61, - title: "Proxy e Interceptação", - level: "advanced", + title: 'Proxy e Interceptação', + level: 'advanced', content: - "Proxy permite interceptar operações como leitura, escrita, e invocação de métodos. " + - "Útil para logging, validation, e lazy loading.", - task: "Crie um proxy para validar propriedades.", - hint: "new Proxy(target, { get, set })", + 'Proxy permite interceptar operações como leitura, escrita, e invocação de métodos. ' + + 'Útil para logging, validation, e lazy loading.', + task: 'Crie um proxy para validar propriedades.', + hint: 'new Proxy(target, { get, set })', starterCode: `interface User { name: string age: number @@ -2114,12 +2114,12 @@ try { }, { id: 62, - title: "Symbol e Metadata", - level: "basic", + title: 'Symbol e Metadata', + level: 'basic', content: - "Symbols são valores únicos que podem servir como chaves de propriedades. " + + 'Symbols são valores únicos que podem servir como chaves de propriedades. ' + 'Úteis para criar propriedades "escondidas" e para reflection.', - task: "Use Symbol para criar uma propriedade privada.", + task: 'Use Symbol para criar uma propriedade privada.', hint: 'const privateKey = Symbol("private")', starterCode: `const nameKey = Symbol("name") const ageKey = Symbol("age") @@ -2156,13 +2156,13 @@ console.log("Cached:", cache.get(key1))`, }, { id: 63, - title: "Asserts Type Guards", - level: "advanced", + title: 'Asserts Type Guards', + level: 'advanced', content: - "Asserts type guards são funções que verificam e refinam tipos, " + - "lançando erro se a condição não for atendida.", - task: "Crie um assert que verifica se um valor é número positivo.", - hint: "function assert(condition, message)", + 'Asserts type guards são funções que verificam e refinam tipos, ' + + 'lançando erro se a condição não for atendida.', + task: 'Crie um assert que verifica se um valor é número positivo.', + hint: 'function assert(condition, message)', starterCode: `function assert(condition: boolean, message: string): asserts condition { if (!condition) { throw new Error(message) @@ -2196,13 +2196,13 @@ console.log("Data length:", data.length)`, }, { id: 64, - title: "Infer com Conditional Types", - level: "advanced", + title: 'Infer com Conditional Types', + level: 'advanced', content: - "`infer` extrai tipos de dentro de outros tipos. " + - "Pode extrair tipos de funções, arrays, promises, e objetos.", - task: "Extraia o tipo de elemento de um array.", - hint: "type ArrayElement = T extends (infer U)[] ? U : never", + '`infer` extrai tipos de dentro de outros tipos. ' + + 'Pode extrair tipos de funções, arrays, promises, e objetos.', + task: 'Extraia o tipo de elemento de um array.', + hint: 'type ArrayElement = T extends (infer U)[] ? U : never', starterCode: `type ReturnTypeOf = T extends (...args: any[]) => infer R ? R : never type ParametersOf = T extends (...args: infer P) => any ? P : never type ArrayElement = T extends (infer U)[] ? U : never @@ -2235,13 +2235,13 @@ console.log("Promise:", pv)`, }, { id: 65, - title: "Type-safe Event Bus", - level: "advanced", + title: 'Type-safe Event Bus', + level: 'advanced', content: - "Crie um event bus que garante type safety para eventos e handlers. " + - "Use mapped types para derivar tipos de eventos.", - task: "Implemente um event bus com subscribe e emit type-safe.", - hint: "Use keyof e generics para inferência.", + 'Crie um event bus que garante type safety para eventos e handlers. ' + + 'Use mapped types para derivar tipos de eventos.', + task: 'Implemente um event bus com subscribe e emit type-safe.', + hint: 'Use keyof e generics para inferência.', starterCode: `type Events = { login: { userId: number; timestamp: Date } logout: { userId: number } @@ -2296,13 +2296,13 @@ bus.emit("purchase", { userId: 1, amount: 99.99 })`, }, { id: 66, - title: "Readonly Deep", - level: "advanced", + title: 'Readonly Deep', + level: 'advanced', content: - "Crie um tipo que torna todas as propriedades aninhadas readonly recursivamente. " + - "Útil para garantir imutabilidade em objetos complexos.", - task: "Crie um tipo DeepReadonly.", - hint: "type DeepReadonly = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K] }", + 'Crie um tipo que torna todas as propriedades aninhadas readonly recursivamente. ' + + 'Útil para garantir imutabilidade em objetos complexos.', + task: 'Crie um tipo DeepReadonly.', + hint: 'type DeepReadonly = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K] }', starterCode: `type DeepReadonly = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K] } @@ -2338,13 +2338,13 @@ company.employees.push({ name: "New", role: "Manager" })`, }, { id: 67, - title: "Strict Null Checks em filters", - level: "basic", + title: 'Strict Null Checks em filters', + level: 'basic', content: - "Filtrar arrays pode criar tipos union com undefined. " + - "Aprenda a usar type guards para refiná-los corretamente.", - task: "Filtre valores nulos e refine o tipo.", - hint: "arr.filter((x): x is Type => x !== null)", + 'Filtrar arrays pode criar tipos union com undefined. ' + + 'Aprenda a usar type guards para refiná-los corretamente.', + task: 'Filtre valores nulos e refine o tipo.', + hint: 'arr.filter((x): x is Type => x !== null)', starterCode: `interface User { id: number name: string @@ -2380,12 +2380,12 @@ if (result) { }, { id: 68, - title: "Enum vs Union vs Const Object", - level: "basic", + title: 'Enum vs Union vs Const Object', + level: 'basic', content: - "Compare enums, union types, e objetos const para entender quando usar cada um. " + - "Cada abordagem tem prós e contras em termos de runtime e type safety.", - task: "Converta um enum para union type e compare.", + 'Compare enums, union types, e objetos const para entender quando usar cada um. ' + + 'Cada abordagem tem prós e contras em termos de runtime e type safety.', + task: 'Converta um enum para union type e compare.', hint: 'type Direction = "N" | "S" | "E" | "W"', starterCode: `enum DirectionEnum { North = "N", @@ -2420,13 +2420,13 @@ console.log("All approaches work!")`, }, { id: 69, - title: "Type-safe CSV Parser", - level: "advanced", + title: 'Type-safe CSV Parser', + level: 'advanced', content: - "Crie um parser de CSV que infere tipos de colunas. " + - "Use generics para mapear headers para tipos.", - task: "Parse CSV e infira tipos das colunas.", - hint: "function parseCSV(csv: string): T[]", + 'Crie um parser de CSV que infere tipos de colunas. ' + + 'Use generics para mapear headers para tipos.', + task: 'Parse CSV e infira tipos das colunas.', + hint: 'function parseCSV(csv: string): T[]', starterCode: `interface User { id: number name: string @@ -2470,13 +2470,13 @@ console.log("First user:", first)`, }, { id: 70, - title: "Schema Validation com Mapped Types", - level: "advanced", + title: 'Schema Validation com Mapped Types', + level: 'advanced', content: - "Crie um schema validator que verifica objetos contra definições de tipos. " + - "Use mapped types para transformar o schema em validadores.", - task: "Valide um objeto contra um schema.", - hint: "Use Record para mapear campos para validadores.", + 'Crie um schema validator que verifica objetos contra definições de tipos. ' + + 'Use mapped types para transformar o schema em validadores.', + task: 'Valide um objeto contra um schema.', + hint: 'Use Record para mapear campos para validadores.', starterCode: `type Validator = (value: unknown) => T type Schema = { @@ -2530,13 +2530,13 @@ console.log("Validated:", validated)`, }, { id: 71, - title: "Polymorphic this Types", - level: "advanced", + title: 'Polymorphic this Types', + level: 'advanced', content: - "Use `this` como tipo de retorno para criar fluent APIs onde métodos retornam " + - "a classe concreta, não a classe base. Útil para herança.", - task: "Crie uma fluent API com this polimórfico.", - hint: "class Builder { add(): this { } }", + 'Use `this` como tipo de retorno para criar fluent APIs onde métodos retornam ' + + 'a classe concreta, não a classe base. Útil para herança.', + task: 'Crie uma fluent API com this polimórfico.', + hint: 'class Builder { add(): this { } }', starterCode: `class Builder { protected parts: string[] = [] @@ -2599,13 +2599,13 @@ console.log("Result:", calc.result())`, }, { id: 72, - title: "Tuple Types em Funções", - level: "basic", + title: 'Tuple Types em Funções', + level: 'basic', content: - "Tuplas podem ser usadas para tipar parâmetros de funções com múltiplos valores. " + - "Útil para funções que retornam múltiplos valores.", - task: "Crie uma função que retorna nome e idade como tupla.", - hint: "function getPerson(): [string, number] { }", + 'Tuplas podem ser usadas para tipar parâmetros de funções com múltiplos valores. ' + + 'Útil para funções que retornam múltiplos valores.', + task: 'Crie uma função que retorna nome e idade como tupla.', + hint: 'function getPerson(): [string, number] { }', starterCode: `function getUser(): [string, number, boolean] { return ["Alice", 25, true] } @@ -2642,13 +2642,13 @@ console.log("Parsed:", date)`, }, { id: 73, - title: "Interface vs Type Alias", - level: "basic", + title: 'Interface vs Type Alias', + level: 'basic', content: - "Interfaces são melhores para objetos e classes, permitindo extends e merge. " + - "Type aliases são melhores para unions, intersections, e tipos primitivos.", - task: "Compare interface e type para o mesmo objeto.", - hint: "interface para objetos, type para unions", + 'Interfaces são melhores para objetos e classes, permitindo extends e merge. ' + + 'Type aliases são melhores para unions, intersections, e tipos primitivos.', + task: 'Compare interface e type para o mesmo objeto.', + hint: 'interface para objetos, type para unions', starterCode: `interface UserI { name: string age: number @@ -2685,12 +2685,12 @@ console.log("Pair:", pair)`, }, { id: 74, - title: "Module Resolution", - level: "advanced", + title: 'Module Resolution', + level: 'advanced', content: - "TypeScript resolve módulos de diferentes formas: classic, node, node16, nodenext. " + - "Entenda as diferenças para configurar projetos corretamente.", - task: "Configure paths e baseUrl para imports.", + 'TypeScript resolve módulos de diferentes formas: classic, node, node16, nodenext. ' + + 'Entenda as diferenças para configurar projetos corretamente.', + task: 'Configure paths e baseUrl para imports.', hint: 'Configure "baseUrl" e "paths" no tsconfig.json', starterCode: `// Simulando paths do tsconfig // { @@ -2726,12 +2726,12 @@ console.log("Resolved @/components:", resolvePath("@/components"))`, }, { id: 75, - title: "Ambient Modules e Triple-Slash", - level: "advanced", + title: 'Ambient Modules e Triple-Slash', + level: 'advanced', content: - "Use triple-slash directives para declarar dependências de módulos. " + - "Útil para incluir tipos e módulos em arquivos compilados.", - task: "Use triple-slash para declarar um módulo.", + 'Use triple-slash directives para declarar dependências de módulos. ' + + 'Útil para incluir tipos e módulos em arquivos compilados.', + task: 'Use triple-slash para declarar um módulo.', hint: '/// ', starterCode: `/// @@ -2754,13 +2754,13 @@ console.log("Ambient declarations loaded!")`, }, { id: 76, - title: "Union Narrowing com never", - level: "advanced", + title: 'Union Narrowing com never', + level: 'advanced', content: - "Use `never` em unions para forçar o TypeScript a verificar todos os casos. " + - "Útil em switch statements exaustivos.", - task: "Crie um switch exaustivo.", - hint: "default: const _: never = value", + 'Use `never` em unions para forçar o TypeScript a verificar todos os casos. ' + + 'Útil em switch statements exaustivos.', + task: 'Crie um switch exaustivo.', + hint: 'default: const _: never = value', starterCode: `type Shape = | { kind: "circle"; radius: number } | { kind: "square"; side: number } @@ -2790,13 +2790,13 @@ shapes.forEach(s => console.log(\`Area: \${area(s).toFixed(2)}\`))`, }, { id: 77, - title: "Type-safe Event Listeners", - level: "advanced", + title: 'Type-safe Event Listeners', + level: 'advanced', content: - "Crie funções que adicionam event listeners com type safety total. " + - "O handler deve ter o tipo correto baseado no evento.", - task: "Crie uma função addEventListener type-safe.", - hint: "Use generics para inferir o handler type.", + 'Crie funções que adicionam event listeners com type safety total. ' + + 'O handler deve ter o tipo correto baseado no evento.', + task: 'Crie uma função addEventListener type-safe.', + hint: 'Use generics para inferir o handler type.', starterCode: `type EventMap = { click: { x: number; y: number } keydown: { key: string } @@ -2833,13 +2833,13 @@ on("focus", () => console.log("focused"))`, }, { id: 78, - title: "Intersection Types com Mixins", - level: "advanced", + title: 'Intersection Types com Mixins', + level: 'advanced', content: - "Intersection types combinam múltiplos tipos em um. " + - "Útil para adicionar funcionalidades via mixins ou criar tipos compuestos.", - task: "Crie um tipo que é both Serializable e Validatable.", - hint: "type T = Serializable & Validatable", + 'Intersection types combinam múltiplos tipos em um. ' + + 'Útil para adicionar funcionalidades via mixins ou criar tipos compuestos.', + task: 'Crie um tipo que é both Serializable e Validatable.', + hint: 'type T = Serializable & Validatable', starterCode: `interface Serializable { toJSON(): Record } @@ -2894,13 +2894,13 @@ io.write("hello")`, }, { id: 79, - title: "Type-safe Console Methods", - level: "basic", + title: 'Type-safe Console Methods', + level: 'basic', content: - "TypeScript não verifica console por padrão. " + - "Crie wrappers type-safe para logging consistente.", - task: "Crie funções de log type-safe.", - hint: "function log(message: T): void", + 'TypeScript não verifica console por padrão. ' + + 'Crie wrappers type-safe para logging consistente.', + task: 'Crie funções de log type-safe.', + hint: 'function log(message: T): void', starterCode: `function log(message: T): void { console.log(\`[LOG] \${message}\`) } @@ -2930,13 +2930,13 @@ console.log("Result:", result)`, }, { id: 80, - title: "Pattern Matching Simples", - level: "basic", + title: 'Pattern Matching Simples', + level: 'basic', content: - "Implemente um pattern matching simples com generics. " + - "Similar ao match em linguagens funcionais.", - task: "Crie uma função match que execute patterns.", - hint: "function match(value: T, patterns: Record): R", + 'Implemente um pattern matching simples com generics. ' + + 'Similar ao match em linguagens funcionais.', + task: 'Crie uma função match que execute patterns.', + hint: 'function match(value: T, patterns: Record): R', starterCode: `function match(value: T, patterns: Record): R { if (value in patterns) { return patterns[value] @@ -2981,13 +2981,13 @@ console.log(reduce({ type: "reset" }))`, }, { id: 81, - title: "Variadic Tuple Types", - level: "advanced", + title: 'Variadic Tuple Types', + level: 'advanced', content: - "Variadic tuples permitem criar tipos que aceitam número variável de elementos. " + - "Útil para concatenação de tipos e tail recursion.", - task: "Crie um tipo que concatena tuplas.", - hint: "type Concat = [...T, ...U]", + 'Variadic tuples permitem criar tipos que aceitam número variável de elementos. ' + + 'Útil para concatenação de tipos e tail recursion.', + task: 'Crie um tipo que concatena tuplas.', + hint: 'type Concat = [...T, ...U]', starterCode: `type Concat = [...T, ...U] type A = Concat<[1, 2], [3, 4]> @@ -3013,13 +3013,13 @@ const d: D = [2, 3]`, }, { id: 82, - title: "Awaited Type para Promises", - level: "advanced", + title: 'Awaited Type para Promises', + level: 'advanced', content: - "O utility type `Awaited` extrai o tipo resolvido de uma Promise. " + - "Funciona recursivamente para Promises aninhadas.", - task: "Use Awaited para tipar o resultado de async functions.", - hint: "type Result = Awaited>", + 'O utility type `Awaited` extrai o tipo resolvido de uma Promise. ' + + 'Funciona recursivamente para Promises aninhadas.', + task: 'Use Awaited para tipar o resultado de async functions.', + hint: 'type Result = Awaited>', starterCode: `type Awaited = T extends Promise ? Awaited : T async function fetchUser(): Promise<{ id: number; name: string }> { @@ -3048,11 +3048,11 @@ getData()`, }, { id: 83, - title: "Brand Keys em Mapped Types", - level: "advanced", + title: 'Brand Keys em Mapped Types', + level: 'advanced', content: - "Use template literal types em mapped types para criar transformações de chaves. " + - "Útil para adicionar prefixos/sufixos ou converter convenções.", + 'Use template literal types em mapped types para criar transformações de chaves. ' + + 'Útil para adicionar prefixos/sufixos ou converter convenções.', task: "Crie um mapped type que adiciona prefixo 'get' a métodos.", hint: "type WithGetters = { [K in keyof T as 'get' + K]: () => T[K] }", starterCode: `type WithGetters = { @@ -3092,13 +3092,13 @@ setters.setName("Bob")`, }, { id: 84, - title: "Type-safe React-like setState", - level: "advanced", + title: 'Type-safe React-like setState', + level: 'advanced', content: - "Implemente um hook de estado similar ao useState do React. " + - "O setter deve permitir update parcial e inferir tipos corretamente.", - task: "Crie um useState simplificado com tipos inferidos.", - hint: "function useState(initial: T): [() => T, (value: T | ((prev: T) => T)) => void]", + 'Implemente um hook de estado similar ao useState do React. ' + + 'O setter deve permitir update parcial e inferir tipos corretamente.', + task: 'Crie um useState simplificado com tipos inferidos.', + hint: 'function useState(initial: T): [() => T, (value: T | ((prev: T) => T)) => void]', starterCode: `function useState(initial: T) { let state = initial @@ -3131,13 +3131,13 @@ console.log("Final count:", count())`, }, { id: 85, - title: "Deep Partial Type", - level: "advanced", + title: 'Deep Partial Type', + level: 'advanced', content: - "Partial torna propriedades de primeiro nível opcionais. " + - "DeepPartial torna TODAS as propriedades aninhadas opcionais recursivamente.", - task: "Crie um tipo DeepPartial.", - hint: "type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] }", + 'Partial torna propriedades de primeiro nível opcionais. ' + + 'DeepPartial torna TODAS as propriedades aninhadas opcionais recursivamente.', + task: 'Crie um tipo DeepPartial.', + hint: 'type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] }', starterCode: `type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] } @@ -3191,13 +3191,13 @@ function updateCompany(current: Company, updates: PartialCompany): Company { }, { id: 86, - title: "Extract Keys por Tipo de Valor", - level: "advanced", + title: 'Extract Keys por Tipo de Valor', + level: 'advanced', content: - "Crie um tipo que extrai chaves de um objeto baseado no tipo de seus valores. " + - "Útil para encontrar campos de um certo tipo.", - task: "Extraia chaves cujos valores são do tipo string.", - hint: "type KeysOfType = { [K in keyof T]: T[K] extends U ? K : never }[keyof T]", + 'Crie um tipo que extrai chaves de um objeto baseado no tipo de seus valores. ' + + 'Útil para encontrar campos de um certo tipo.', + task: 'Extraia chaves cujos valores são do tipo string.', + hint: 'type KeysOfType = { [K in keyof T]: T[K] extends U ? K : never }[keyof T]', starterCode: `type KeysOfType = { [K in keyof T]: T[K] extends U ? K : never }[keyof T] @@ -3240,12 +3240,12 @@ console.log("Numbers:", numbers)`, }, { id: 87, - title: "Type-safe Redux-like Reducer", - level: "advanced", + title: 'Type-safe Redux-like Reducer', + level: 'advanced', content: - "Implemente um reducer type-safe similar ao Redux. " + - "O tipo de ação determina quais payloads são válidos.", - task: "Crie um reducer com actions type-safe.", + 'Implemente um reducer type-safe similar ao Redux. ' + + 'O tipo de ação determina quais payloads são válidos.', + task: 'Crie um reducer com actions type-safe.', hint: 'type Action = { type: "TYPE"; payload: T }', starterCode: `type Action = | { type: "increment"; payload: number } @@ -3296,13 +3296,13 @@ console.log("After reset:", state.count)`, }, { id: 88, - title: "Constructor Parameters Type", - level: "advanced", + title: 'Constructor Parameters Type', + level: 'advanced', content: - "`ConstructorParameters` extrai os tipos de parâmetros do construtor de T. " + - "Útil para criar factories e injeção de dependência.", - task: "Use ConstructorParameters para criar uma factory.", - hint: "type CtorParams = ConstructorParameters", + '`ConstructorParameters` extrai os tipos de parâmetros do construtor de T. ' + + 'Útil para criar factories e injeção de dependência.', + task: 'Use ConstructorParameters para criar uma factory.', + hint: 'type CtorParams = ConstructorParameters', starterCode: `type ConstructorParameters any> = T extends new (...args: infer P) => any ? P : never @@ -3343,13 +3343,13 @@ console.log("Product:", product.name, product.price)`, }, { id: 89, - title: "Optional Keys e Required Keys", - level: "advanced", + title: 'Optional Keys e Required Keys', + level: 'advanced', content: - "`Required` torna todas as propriedades obrigatórias. " + - "`Optional` (custom) pode fazer o oposto, ou criar tipos que têm apenas opcionais.", - task: "Extraia chaves opcionais e obrigatórias separadamente.", - hint: "type OptionalKeys = { [K in keyof T]: T extends { [K]: T[K] } ? never : K }[keyof T]", + '`Required` torna todas as propriedades obrigatórias. ' + + '`Optional` (custom) pode fazer o oposto, ou criar tipos que têm apenas opcionais.', + task: 'Extraia chaves opcionais e obrigatórias separadamente.', + hint: 'type OptionalKeys = { [K in keyof T]: T extends { [K]: T[K] } ? never : K }[keyof T]', starterCode: `type OptionalKeys = { [K in keyof T]: {} extends Pick ? K : never }[keyof T] @@ -3387,13 +3387,13 @@ console.log("Validation:", result)`, }, { id: 90, - title: "Type-safe Event Bus Final", - level: "advanced", + title: 'Type-safe Event Bus Final', + level: 'advanced', content: - "Combine tudo: generics, conditional types, e mapped types " + - "para criar um event bus completamente type-safe.", - task: "Crie um event bus com inferred handlers.", - hint: "Use infer para extrair tipos de eventos.", + 'Combine tudo: generics, conditional types, e mapped types ' + + 'para criar um event bus completamente type-safe.', + task: 'Crie um event bus com inferred handlers.', + hint: 'Use infer para extrair tipos de eventos.', starterCode: `type EventMap = Record type EventReceiver = (params: T) => void @@ -3445,13 +3445,13 @@ bus.emit("purchase", { amount: 99.99, item: "E-book" })`, }, { id: 91, - title: "Omit vs Exclude", - level: "basic", + title: 'Omit vs Exclude', + level: 'basic', content: - "`Omit` remove propriedades de um tipo objeto. " + - "`Exclude` remove tipos de uma union. Entenda a diferença.", - task: "Use Omit para objeto e Exclude para union.", - hint: "Omit para objetos, Exclude para unions", + '`Omit` remove propriedades de um tipo objeto. ' + + '`Exclude` remove tipos de uma union. Entenda a diferença.', + task: 'Use Omit para objeto e Exclude para union.', + hint: 'Omit para objetos, Exclude para unions', starterCode: `interface User { id: number name: string @@ -3485,13 +3485,13 @@ console.log("Primary colors:", primaries)`, }, { id: 92, - title: "Object.entries e Object.keys Tipados", - level: "basic", + title: 'Object.entries e Object.keys Tipados', + level: 'basic', content: - "Object.entries e Object.keys retornam `string[]` por padrão. " + - "Use assertion ou generics para tipá-los corretamente.", - task: "Itere sobre um objeto com tipos corretos.", - hint: "Use as Array<[keyof T, T[keyof T]]>", + 'Object.entries e Object.keys retornam `string[]` por padrão. ' + + 'Use assertion ou generics para tipá-los corretamente.', + task: 'Itere sobre um objeto com tipos corretos.', + hint: 'Use as Array<[keyof T, T[keyof T]]>', starterCode: `interface User { id: number name: string @@ -3526,13 +3526,13 @@ typedEntries({ a: 1, b: 2, c: 3 }).forEach(([k, v]) => { }, { id: 93, - title: "Strict Property Initialization", - level: "basic", + title: 'Strict Property Initialization', + level: 'basic', content: - "Com strictPropertyInitialization, propriedades de classe devem ser inicializadas " + - "no construtor ou com initialization shorthand.", - task: "Inicialize propriedades corretamente.", - hint: "Use constructor ou initialization shorthand.", + 'Com strictPropertyInitialization, propriedades de classe devem ser inicializadas ' + + 'no construtor ou com initialization shorthand.', + task: 'Inicialize propriedades corretamente.', + hint: 'Use constructor ou initialization shorthand.', starterCode: `class User { name: string age: number @@ -3577,13 +3577,13 @@ console.log("Name:", opt.name)`, }, { id: 94, - title: "Type-safe Fetch Wrapper", - level: "advanced", + title: 'Type-safe Fetch Wrapper', + level: 'advanced', content: - "Crie um wrapper type-safe para fetch que infere o tipo de resposta. " + - "Suporta JSON, texto, e verificação de status.", - task: "Crie uma função fetchJson type-safe.", - hint: "async function fetchJson(url: string): Promise", + 'Crie um wrapper type-safe para fetch que infere o tipo de resposta. ' + + 'Suporta JSON, texto, e verificação de status.', + task: 'Crie uma função fetchJson type-safe.', + hint: 'async function fetchJson(url: string): Promise', starterCode: `async function fetchJson( url: string, options?: RequestInit @@ -3634,13 +3634,13 @@ main()`, }, { id: 95, - title: "Type-safe Route Handler", - level: "advanced", + title: 'Type-safe Route Handler', + level: 'advanced', content: - "Crie um router type-safe onde cada rota tem seu handler com tipos específicos. " + - "O handler recebe apenas os parâmetros definidos para aquela rota.", - task: "Crie handlers de rota type-safe.", - hint: "Use Record para mapear rotas para handlers.", + 'Crie um router type-safe onde cada rota tem seu handler com tipos específicos. ' + + 'O handler recebe apenas os parâmetros definidos para aquela rota.', + task: 'Crie handlers de rota type-safe.', + hint: 'Use Record para mapear rotas para handlers.', starterCode: `type RouteHandler = (params: T) => string | Promise interface Route { @@ -3695,12 +3695,12 @@ console.log(matchRoute("/posts/456?draft=true", routes))`, }, { id: 96, - title: "Generic Record Factory", - level: "advanced", + title: 'Generic Record Factory', + level: 'advanced', content: - "Crie uma factory que gera objetos tipados com métodos úteis. " + - "O tipo de retorno deve ser completamente inferido.", - task: "Crie uma factory para gerar objetos com IDs.", + 'Crie uma factory que gera objetos tipados com métodos úteis. ' + + 'O tipo de retorno deve ser completamente inferido.', + task: 'Crie uma factory para gerar objetos com IDs.', hint: 'function create(data: Omit): T & { id: string }', starterCode: `function createEntity( data: T @@ -3756,13 +3756,13 @@ console.log("Numbers:", [...numbers])`, }, { id: 97, - title: "Reverse Engineering Types", - level: "advanced", + title: 'Reverse Engineering Types', + level: 'advanced', content: - "Dado um objeto, derive seu tipo automaticamente. " + - "Use `typeof` para criar tipos a partir de valores.", - task: "Use typeof para criar tipos a partir de objetos.", - hint: "type T = typeof myObject", + 'Dado um objeto, derive seu tipo automaticamente. ' + + 'Use `typeof` para criar tipos a partir de valores.', + task: 'Use typeof para criar tipos a partir de objetos.', + hint: 'type T = typeof myObject', starterCode: `const user = { id: 1, name: "Alice", @@ -3812,12 +3812,12 @@ type Method = typeof constObj.GET | typeof constObj.POST`, }, { id: 98, - title: "Chaining Optionals", - level: "basic", + title: 'Chaining Optionals', + level: 'basic', content: - "Ao acessar propriedades opcionais aninhadas, você pode usar optional chaining " + - "para evitar erros. Aprenda a lidar com undefined em profundidades.", - task: "Acesse propriedades profundas com safety.", + 'Ao acessar propriedades opcionais aninhadas, você pode usar optional chaining ' + + 'para evitar erros. Aprenda a lidar com undefined em profundidades.', + task: 'Acesse propriedades profundas com safety.', hint: 'user?.address?.city ?? "unknown"', starterCode: `interface User { name: string @@ -3861,13 +3861,13 @@ console.log("getCity:", getCity(user1), getCity(user2))`, }, { id: 99, - title: "Type-safe Event-Driven Architecture", - level: "advanced", + title: 'Type-safe Event-Driven Architecture', + level: 'advanced', content: - "Crie um sistema de eventos onde emissores e listeners são type-safe. " + - "O tipo de evento determina os dados disponíveis.", - task: "Implemente subscribe/publish com tipos derivados.", - hint: "Use generic para relacionar evento e dados.", + 'Crie um sistema de eventos onde emissores e listeners são type-safe. ' + + 'O tipo de evento determina os dados disponíveis.', + task: 'Implemente subscribe/publish com tipos derivados.', + hint: 'Use generic para relacionar evento e dados.', starterCode: `type EventMap = { userCreated: { id: number; email: string } userUpdated: { id: number; changes: Record } @@ -3915,14 +3915,14 @@ emitter.emit("userUpdated", { id: 1, changes: { name: "Alice", age: 26 } })`, }, { id: 100, - title: "Conclusão: Próximos Passos", - level: "basic", - content: - "Parabéns por completar 100 lições de TypeScript! Agora você tem uma base sólida. " + - "Próximos passos: contribua com projetos open source, explore bibliotecas como React/Next.js, " + - "e pratique com desafios de código.", - task: "Revise o que aprendeu e continue praticando!", - hint: "Prática leva à maestria!", + title: 'Conclusão: Próximos Passos', + level: 'basic', + content: + 'Parabéns por completar 100 lições de TypeScript! Agora você tem uma base sólida. ' + + 'Próximos passos: contribua com projetos open source, explore bibliotecas como React/Next.js, ' + + 'e pratique com desafios de código.', + task: 'Revise o que aprendeu e continue praticando!', + hint: 'Prática leva à maestria!', starterCode: `console.log("🎉 Parabéns!") console.log("") console.log("Você completou 100 lições de TypeScript!") @@ -3950,13 +3950,13 @@ console.log("Boa jornada! 🚀")`, }, { id: 101, - title: " typeof com Objetos", - level: "medium", + title: ' typeof com Objetos', + level: 'medium', content: - "Use `typeof` para obter o tipo de uma variável ou objeto. " + - "Isso cria um tipo automaticamente baseado no valor.", - task: "Obtenha o tipo de um objeto usando typeof.", - hint: "type T = typeof myObject", + 'Use `typeof` para obter o tipo de uma variável ou objeto. ' + + 'Isso cria um tipo automaticamente baseado no valor.', + task: 'Obtenha o tipo de um objeto usando typeof.', + hint: 'type T = typeof myObject', starterCode: `const user = { name: "Alice", age: 25, @@ -3975,13 +3975,13 @@ console.log("New user:", newUser)`, }, { id: 102, - title: " Operador && e ||", - level: "medium", + title: ' Operador && e ||', + level: 'medium', content: - "Operadores lógicos funcionam como em JavaScript. " + - "Aprenda a usá-los com tipos condicionais.", - task: "Use operadores lógicos em expressões.", - hint: "const result = a && b || c", + 'Operadores lógicos funcionam como em JavaScript. ' + + 'Aprenda a usá-los com tipos condicionais.', + task: 'Use operadores lógicos em expressões.', + hint: 'const result = a && b || c', starterCode: `const a = true const b = false const c = true @@ -4000,13 +4000,13 @@ console.log("OR result:", orResult)`, }, { id: 103, - title: " Ternary Operator", - level: "medium", + title: ' Ternary Operator', + level: 'medium', content: - "O operador ternário `condição ? valor1 : valor2` é útil para condições simples. " + - "Também pode ser usado em tipos com conditional types.", - task: "Use o operador ternário para escolher valores.", - hint: "const result = condition ? value1 : value2", + 'O operador ternário `condição ? valor1 : valor2` é útil para condições simples. ' + + 'Também pode ser usado em tipos com conditional types.', + task: 'Use o operador ternário para escolher valores.', + hint: 'const result = condition ? value1 : value2', starterCode: `const age = 18 const status = age >= 18 ? "adult" : "minor" console.log("Status:", status) @@ -4024,13 +4024,13 @@ console.log(hasItems)`, }, { id: 104, - title: " Arrow Functions", - level: "medium", + title: ' Arrow Functions', + level: 'medium', content: - "Arrow functions são funções anônimas mais sintéticas. " + - "TypeScript infere tipos de parâmetros e retorno.", - task: "Crie arrow functions tipadas.", - hint: "const fn = (x: number): number => x * 2", + 'Arrow functions são funções anônimas mais sintéticas. ' + + 'TypeScript infere tipos de parâmetros e retorno.', + task: 'Crie arrow functions tipadas.', + hint: 'const fn = (x: number): number => x * 2', starterCode: `const add = (a: number, b: number): number => a + b const greet = (name: string): string => \`Hello, \${name}!\` const double = (x: number) => x * 2 @@ -4048,13 +4048,13 @@ console.log(process(numbers, double))`, }, { id: 105, - title: " Spread em Objetos", - level: "medium", + title: ' Spread em Objetos', + level: 'medium', content: - "O spread operator `...` copia propriedades de objetos. " + - "Útil para criar cópias e mesclar objetos.", - task: "Use spread para mesclar objetos.", - hint: "const merged = { ...obj1, ...obj2 }", + 'O spread operator `...` copia propriedades de objetos. ' + + 'Útil para criar cópias e mesclar objetos.', + task: 'Use spread para mesclar objetos.', + hint: 'const merged = { ...obj1, ...obj2 }', starterCode: `const defaults = { theme: "dark", language: "pt-BR" } const userPrefs = { theme: "light" } @@ -4072,13 +4072,13 @@ console.log("Full:", full)`, }, { id: 106, - title: " Spread em Arrays", - level: "medium", + title: ' Spread em Arrays', + level: 'medium', content: - "Spread em arrays cria novas cópias ou concatena arrays. " + - "Não modifica o array original (imutabilidade).", - task: "Use spread para manipular arrays.", - hint: "const combined = [...arr1, ...arr2]", + 'Spread em arrays cria novas cópias ou concatena arrays. ' + + 'Não modifica o array original (imutabilidade).', + task: 'Use spread para manipular arrays.', + hint: 'const combined = [...arr1, ...arr2]', starterCode: `const arr1 = [1, 2, 3] const arr2 = [4, 5, 6] @@ -4097,13 +4097,13 @@ console.log("Doubled:", updated)`, }, { id: 107, - title: " Destructuring de Objetos", - level: "medium", + title: ' Destructuring de Objetos', + level: 'medium', content: - "Destructuring extrai propriedades de objetos em variáveis. " + - "Pode usar valores padrão para propriedades opcionais.", - task: "Extraia propriedades de um objeto.", - hint: "const { name, age } = user", + 'Destructuring extrai propriedades de objetos em variáveis. ' + + 'Pode usar valores padrão para propriedades opcionais.', + task: 'Extraia propriedades de um objeto.', + hint: 'const { name, age } = user', starterCode: `const user = { name: "Alice", age: 25, @@ -4124,13 +4124,13 @@ console.log(greet(user))`, }, { id: 108, - title: " Destructuring de Arrays", - level: "medium", + title: ' Destructuring de Arrays', + level: 'medium', content: - "Destructuring de arrays usa posição, não nomes. " + - "Pode ignorar elementos ou usar rest parameters.", - task: "Extraia elementos de um array por posição.", - hint: "const [first, second] = arr", + 'Destructuring de arrays usa posição, não nomes. ' + + 'Pode ignorar elementos ou usar rest parameters.', + task: 'Extraia elementos de um array por posição.', + hint: 'const [first, second] = arr', starterCode: `const coords = [10, 20, 30] const [x, y, z] = coords console.log("Coords:", x, y, z) @@ -4150,13 +4150,13 @@ console.log("Sum:", sum([5, 3]))`, }, { id: 109, - title: " Array Methods - map", - level: "medium", + title: ' Array Methods - map', + level: 'medium', content: - "map cria um novo array transformando cada elemento. " + - "TypeScript infere o tipo do array resultante.", - task: "Use map para transformar um array.", - hint: "const doubled = nums.map(n => n * 2)", + 'map cria um novo array transformando cada elemento. ' + + 'TypeScript infere o tipo do array resultante.', + task: 'Use map para transformar um array.', + hint: 'const doubled = nums.map(n => n * 2)', starterCode: `const numbers = [1, 2, 3, 4, 5] const doubled = numbers.map(n => n * 2) @@ -4187,13 +4187,13 @@ console.log("Birthdays:", birthdays)`, }, { id: 110, - title: " Array Methods - filter", - level: "medium", + title: ' Array Methods - filter', + level: 'medium', content: - "filter cria um novo array com elementos que passam no teste. " + - "TypeScript refina o tipo automaticamente.", - task: "Filtre um array usando filter.", - hint: "const evens = nums.filter(n => n % 2 === 0)", + 'filter cria um novo array com elementos que passam no teste. ' + + 'TypeScript refina o tipo automaticamente.', + task: 'Filtre um array usando filter.', + hint: 'const evens = nums.filter(n => n % 2 === 0)', starterCode: `const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] const evens = numbers.filter(n => n % 2 === 0) @@ -4225,11 +4225,13 @@ console.log("Under 1000:", affordable)`, }, { id: 111, - title: " Array Methods - reduce", - level: "medium", - content: "reduce reduz um array a um único valor. " + "O acumulador pode ser qualquer tipo.", - task: "Some todos os números de um array.", - hint: "const sum = arr.reduce((acc, n) => acc + n, 0)", + title: ' Array Methods - reduce', + level: 'medium', + content: + 'reduce reduz um array a um único valor. ' + + 'O acumulador pode ser qualquer tipo.', + task: 'Some todos os números de um array.', + hint: 'const sum = arr.reduce((acc, n) => acc + n, 0)', starterCode: `const numbers = [1, 2, 3, 4, 5] const sum = numbers.reduce((acc, n) => acc + n, 0) @@ -4263,13 +4265,13 @@ console.log("By age:", byAge)`, }, { id: 112, - title: " Array Methods - find e findIndex", - level: "medium", + title: ' Array Methods - find e findIndex', + level: 'medium', content: - "find retorna o primeiro elemento que satisfaz a condição. " + - "findIndex retorna sua posição.", - task: "Encontre um elemento no array.", - hint: "const found = arr.find(x => x.id === 1)", + 'find retorna o primeiro elemento que satisfaz a condição. ' + + 'findIndex retorna sua posição.', + task: 'Encontre um elemento no array.', + hint: 'const found = arr.find(x => x.id === 1)', starterCode: `const numbers = [10, 20, 30, 40, 50] const found = numbers.find(n => n > 25) @@ -4297,13 +4299,13 @@ console.log("Index:", userIndex)`, }, { id: 113, - title: " Array Methods - some e every", - level: "medium", + title: ' Array Methods - some e every', + level: 'medium', content: - "some retorna true se algum elemento passar no teste. " + - "every retorna true se todos passarem.", - task: "Verifique condições em arrays.", - hint: "const hasEvens = arr.some(n => n % 2 === 0)", + 'some retorna true se algum elemento passar no teste. ' + + 'every retorna true se todos passarem.', + task: 'Verifique condições em arrays.', + hint: 'const hasEvens = arr.some(n => n % 2 === 0)', starterCode: `const numbers = [1, 3, 5, 7, 9] const hasEvens = numbers.some(n => n % 2 === 0) @@ -4334,13 +4336,13 @@ console.log("All available:", allAvailable)`, }, { id: 114, - title: " Array Methods - includes e indexOf", - level: "medium", + title: ' Array Methods - includes e indexOf', + level: 'medium', content: - "includes verifica se um valor existe no array. " + - "indexOf retorna a posição ou -1 se não encontrar.", - task: "Verifique se um valor existe no array.", - hint: "const exists = arr.includes(value)", + 'includes verifica se um valor existe no array. ' + + 'indexOf retorna a posição ou -1 se não encontrar.', + task: 'Verifique se um valor existe no array.', + hint: 'const exists = arr.includes(value)', starterCode: `const fruits = ["apple", "banana", "orange"] console.log("Has banana:", fruits.includes("banana")) @@ -4365,13 +4367,13 @@ console.log("Unique:", unique([1, 2, 2, 3, 3, 3]))`, }, { id: 115, - title: " Array Methods - sort", - level: "medium", + title: ' Array Methods - sort', + level: 'medium', content: - "sort ordena elementos no lugar. " + - "Para ordenação correta, forneça uma função comparadora.", - task: "Ordene um array de números.", - hint: "const sorted = arr.sort((a, b) => a - b)", + 'sort ordena elementos no lugar. ' + + 'Para ordenação correta, forneça uma função comparadora.', + task: 'Ordene um array de números.', + hint: 'const sorted = arr.sort((a, b) => a - b)', starterCode: `const numbers = [5, 2, 8, 1, 9] const ascending = [...numbers].sort((a, b) => a - b) @@ -4399,13 +4401,13 @@ console.log("By age:", byAge.map(u => u.name))`, }, { id: 116, - title: " Array Methods - slice e splice", - level: "medium", + title: ' Array Methods - slice e splice', + level: 'medium', content: - "slice retorna uma cópia de uma porção do array. " + - "splice remove/substitui elementos no lugar.", - task: "Extraia e modifique arrays.", - hint: "const portion = arr.slice(1, 3)", + 'slice retorna uma cópia de uma porção do array. ' + + 'splice remove/substitui elementos no lugar.', + task: 'Extraia e modifique arrays.', + hint: 'const portion = arr.slice(1, 3)', starterCode: `const numbers = [0, 1, 2, 3, 4, 5] const portion = numbers.slice(1, 4) @@ -4430,11 +4432,13 @@ console.log("After insert:", arr2)`, }, { id: 117, - title: " Array Methods - flat", - level: "medium", - content: "flat nivela arrays aninhados. " + "flatMap combina map e flat em uma operação.", - task: "Nivele arrays aninhados.", - hint: "const flat = nested.flat()", + title: ' Array Methods - flat', + level: 'medium', + content: + 'flat nivela arrays aninhados. ' + + 'flatMap combina map e flat em uma operação.', + task: 'Nivele arrays aninhados.', + hint: 'const flat = nested.flat()', starterCode: `const nested = [1, [2, 3], [4, [5, 6]]] const flat1 = nested.flat() @@ -4456,12 +4460,12 @@ console.log("Doubled + 1:", doubledAndPlusOne)`, }, { id: 118, - title: " String Methods", - level: "medium", + title: ' String Methods', + level: 'medium', content: - "Strings têm métodos úteis como split, join, trim, etc. " + - "TypeScript os trata como métodos de string.", - task: "Manipule uma string.", + 'Strings têm métodos úteis como split, join, trim, etc. ' + + 'TypeScript os trata como métodos de string.', + task: 'Manipule uma string.', hint: "str.split(',').join('-')", starterCode: `const text = " Hello, World! " @@ -4485,13 +4489,13 @@ console.log("Slice:", email.slice(0, 4))`, }, { id: 119, - title: " Math e Number", - level: "medium", + title: ' Math e Number', + level: 'medium', content: - "Math fornece funções matemáticas úteis. " + - "Number tem constantes e métodos para converter.", - task: "Use Math e Number para operações.", - hint: "Math.floor(Math.random() * 10)", + 'Math fornece funções matemáticas úteis. ' + + 'Number tem constantes e métodos para converter.', + task: 'Use Math e Number para operações.', + hint: 'Math.floor(Math.random() * 10)', starterCode: `console.log("Round:", Math.round(4.5)) console.log("Floor:", Math.floor(4.9)) console.log("Ceil:", Math.ceil(4.1)) @@ -4512,11 +4516,13 @@ console.log("IsFinite:", Number.isFinite(Infinity))`, }, { id: 120, - title: " Date", - level: "medium", - content: "Date representa datas e tempos. " + "Métodos obtêm componentes individuais.", - task: "Trabalhe com datas.", - hint: "const now = new Date()", + title: ' Date', + level: 'medium', + content: + 'Date representa datas e tempos. ' + + 'Métodos obtêm componentes individuais.', + task: 'Trabalhe com datas.', + hint: 'const now = new Date()', starterCode: `const now = new Date() console.log("Now:", now) console.log("ISO:", now.toISOString()) @@ -4537,12 +4543,13 @@ console.log("After week:", afterWeek.toDateString())`, }, { id: 121, - title: " JSON parse e stringify", - level: "medium", + title: ' JSON parse e stringify', + level: 'medium', content: - "JSON.stringify converte objetos para string. " + "JSON.parse converte string para objeto.", - task: "Serialize e deserialize JSON.", - hint: "JSON.parse(jsonString)", + 'JSON.stringify converte objetos para string. ' + + 'JSON.parse converte string para objeto.', + task: 'Serialize e deserialize JSON.', + hint: 'JSON.parse(jsonString)', starterCode: `const obj = { name: "Alice", age: 25, @@ -4564,13 +4571,13 @@ console.log("User:", user.name)`, }, { id: 122, - title: " Promise.all e Promise.race", - level: "medium", + title: ' Promise.all e Promise.race', + level: 'medium', content: - "Promise.all espera todas as promises resolverem. " + - "Promise.race retorna a primeira que resolver.", - task: "Trabalhe com múltiplas promises.", - hint: "Promise.all([p1, p2])", + 'Promise.all espera todas as promises resolverem. ' + + 'Promise.race retorna a primeira que resolver.', + task: 'Trabalhe com múltiplas promises.', + hint: 'Promise.all([p1, p2])', starterCode: `const p1 = Promise.resolve(1) const p2 = Promise.resolve(2) const p3 = Promise.resolve(3) @@ -4595,13 +4602,13 @@ Promise.allSettled([fail, success]).then(results => { }, { id: 123, - title: " try/catch/finally", - level: "medium", + title: ' try/catch/finally', + level: 'medium', content: - "try executa código, catch trata erros, finally executa sempre. " + - "TypeScript infere o tipo do erro como unknown.", - task: "Trate erros com try/catch.", - hint: "try { } catch (e) { }", + 'try executa código, catch trata erros, finally executa sempre. ' + + 'TypeScript infere o tipo do erro como unknown.', + task: 'Trate erros com try/catch.', + hint: 'try { } catch (e) { }', starterCode: `function divide(a: number, b: number): number { if (b === 0) throw new Error("Division by zero") return a / b @@ -4629,10 +4636,10 @@ console.log(safeParse("invalid"))`, }, { id: 124, - title: " throw e Error", - level: "medium", - content: "throw lança exceções. " + "O tipo Error tem message e name.", - task: "Lance erros personalizados.", + title: ' throw e Error', + level: 'medium', + content: 'throw lança exceções. ' + 'O tipo Error tem message e name.', + task: 'Lance erros personalizados.', hint: "throw new Error('message')", starterCode: `function validateAge(age: number): void { if (age < 0) { @@ -4664,11 +4671,13 @@ try { }, { id: 125, - title: " setTimeout e setInterval", - level: "medium", - content: "setTimeout executa após um delay. " + "setInterval executa repetidamente.", - task: "Agende execução de código.", - hint: "setTimeout(() => {}, 1000)", + title: ' setTimeout e setInterval', + level: 'medium', + content: + 'setTimeout executa após um delay. ' + + 'setInterval executa repetidamente.', + task: 'Agende execução de código.', + hint: 'setTimeout(() => {}, 1000)', starterCode: `console.log("Before timeout") setTimeout(() => { @@ -4689,11 +4698,13 @@ const interval = setInterval(() => { }, { id: 126, - title: " clearTimeout e clearInterval", - level: "medium", - content: "clearTimeout cancela um setTimeout. " + "clearInterval para um setInterval.", - task: "Cancele timers.", - hint: "clearTimeout(timerId)", + title: ' clearTimeout e clearInterval', + level: 'medium', + content: + 'clearTimeout cancela um setTimeout. ' + + 'clearInterval para um setInterval.', + task: 'Cancele timers.', + hint: 'clearTimeout(timerId)', starterCode: `const timeoutId = setTimeout(() => { console.log("This won't print") }, 1000) @@ -4714,13 +4725,13 @@ const intervalId = setInterval(() => { }, { id: 127, - title: " Object.keys, values, entries", - level: "medium", + title: ' Object.keys, values, entries', + level: 'medium', content: - "Object.keys retorna chaves, values retorna valores, " + - "entries retorna pares [key, value].", - task: "Itere sobre as propriedades de um objeto.", - hint: "Object.keys(obj)", + 'Object.keys retorna chaves, values retorna valores, ' + + 'entries retorna pares [key, value].', + task: 'Itere sobre as propriedades de um objeto.', + hint: 'Object.keys(obj)', starterCode: `const user = { name: "Alice", age: 25, @@ -4741,13 +4752,13 @@ Object.entries(user).forEach(([key, value]) => { }, { id: 128, - title: " Object.assign", - level: "medium", + title: ' Object.assign', + level: 'medium', content: - "Object.assign copia propriedades de objetos fonte para um destino. " + - "É similar ao spread operator.", - task: "Copie propriedades entre objetos.", - hint: "Object.assign(target, source)", + 'Object.assign copia propriedades de objetos fonte para um destino. ' + + 'É similar ao spread operator.', + task: 'Copie propriedades entre objetos.', + hint: 'Object.assign(target, source)', starterCode: `const target = { a: 1 } const source = { b: 2, c: 3 } @@ -4766,13 +4777,13 @@ console.log("Clone:", clone)`, }, { id: 129, - title: " Object.freeze e seal", - level: "medium", + title: ' Object.freeze e seal', + level: 'medium', content: - "Object.freeze impede adição/modificação de propriedades. " + - "Object.sele impede adição mas permite modificação.", - task: "Torne um objeto imutável.", - hint: "Object.freeze(obj)", + 'Object.freeze impede adição/modificação de propriedades. ' + + 'Object.sele impede adição mas permite modificação.', + task: 'Torne um objeto imutável.', + hint: 'Object.freeze(obj)', starterCode: `const obj = { name: "Alice", age: 25 } Object.freeze(obj) @@ -4798,11 +4809,13 @@ console.log("Sealed new prop:", sealed.newProp)`, }, { id: 130, - title: " Array.isArray", - level: "medium", - content: "Array.isArray verifica se um valor é um array. " + "Útil para type guards.", - task: "Verifique se algo é um array.", - hint: "Array.isArray(value)", + title: ' Array.isArray', + level: 'medium', + content: + 'Array.isArray verifica se um valor é um array. ' + + 'Útil para type guards.', + task: 'Verifique se algo é um array.', + hint: 'Array.isArray(value)', starterCode: `console.log("Is array:", Array.isArray([1, 2, 3])) console.log("Not array:", Array.isArray("hello")) console.log("Not array:", Array.isArray({ length: 3 })) @@ -4822,13 +4835,13 @@ process({ 0: "a", 1: "b", length: 2 })`, }, { id: 131, - title: " Boolean Coercion", - level: "medium", + title: ' Boolean Coercion', + level: 'medium', content: - "Valores podem ser convertidos para boolean com !! ou Boolean(). " + + 'Valores podem ser convertidos para boolean com !! ou Boolean(). ' + 'Entenda falsy values: false, 0, "", null, undefined, NaN.', - task: "Converta valores para boolean.", - hint: "const bool = !!value", + task: 'Converta valores para boolean.', + hint: 'const bool = !!value', starterCode: `console.log("Boolean of 1:", Boolean(1)) console.log("Boolean of 0:", Boolean(0)) console.log("Boolean of '':", Boolean("")) @@ -4847,12 +4860,12 @@ console.log("Bool:", bool)`, }, { id: 132, - title: " Number Coercion", - level: "medium", + title: ' Number Coercion', + level: 'medium', content: - "Converta strings para números com Number(), parseInt(), parseFloat(). " + - "Entenda a diferença entre eles.", - task: "Converta strings para números.", + 'Converta strings para números com Number(), parseInt(), parseFloat(). ' + + 'Entenda a diferença entre eles.', + task: 'Converta strings para números.', hint: "Number('42') ou parseInt('42')", starterCode: `console.log("Number('42'):", Number("42")) console.log("Number('3.14'):", Number("3.14")) @@ -4872,12 +4885,12 @@ console.log("+ '3.14':", +"3.14")`, }, { id: 133, - title: " String Coercion", - level: "medium", + title: ' String Coercion', + level: 'medium', content: - "Converta valores para string com String() ou toString(). " + - "Template literals também convertem automaticamente.", - task: "Converta valores para string.", + 'Converta valores para string com String() ou toString(). ' + + 'Template literals também convertem automaticamente.', + task: 'Converta valores para string.', hint: "String(42) ou 42 + ''", starterCode: `console.log("String(42):", String(42)) console.log("String(true):", String(true)) @@ -4897,13 +4910,13 @@ console.log("\`Bool: \${bool}\`:", \`Bool: \${bool}\`)`, }, { id: 134, - title: " Default Parameters", - level: "medium", + title: ' Default Parameters', + level: 'medium', content: - "Parâmetros com valor padrão são usados quando o argumento é undefined. " + - "Diferente de opcionais (?), que podem ser omitidos completamente.", - task: "Use parâmetros com valor padrão.", - hint: "function fn(a: number = 10)", + 'Parâmetros com valor padrão são usados quando o argumento é undefined. ' + + 'Diferente de opcionais (?), que podem ser omitidos completamente.', + task: 'Use parâmetros com valor padrão.', + hint: 'function fn(a: number = 10)', starterCode: `function greet(name: string = "World"): string { return \`Hello, \${name}!\` } @@ -4927,13 +4940,13 @@ console.log(createUser("Charlie", 25))`, }, { id: 135, - title: " Rest Parameters", - level: "medium", + title: ' Rest Parameters', + level: 'medium', content: - "Rest parameters收集 múltiplos argumentos em um array. " + - "Útil para funções com número variável de parâmetros.", - task: "Crie uma função com rest parameters.", - hint: "function fn(...args: number[])", + 'Rest parameters收集 múltiplos argumentos em um array. ' + + 'Útil para funções com número variável de parâmetros.', + task: 'Crie uma função com rest parameters.', + hint: 'function fn(...args: number[])', starterCode: `function sum(...numbers: number[]): number { return numbers.reduce((a, b) => a + b, 0) } @@ -4953,13 +4966,13 @@ console.log("Spread:", sum(...arr))`, }, { id: 136, - title: " Arguments Object", - level: "medium", + title: ' Arguments Object', + level: 'medium', content: - "arguments é um objeto array-like disponível em funções normais. " + - "Arrow functions não têm arguments.", - task: "Acesse argumentos via arguments.", - hint: "function fn() { console.log(arguments) }", + 'arguments é um objeto array-like disponível em funções normais. ' + + 'Arrow functions não têm arguments.', + task: 'Acesse argumentos via arguments.', + hint: 'function fn() { console.log(arguments) }', starterCode: `function sum(): number { let total = 0 for (let i = 0; i < arguments.length; i++) { @@ -4979,11 +4992,13 @@ showArgs(1, "hello", true)`, }, { id: 137, - title: " IIFE - Immediately Invoked Function", - level: "medium", - content: "IIFE é uma função que executa imediatamente. " + "Útil para criar escopo privado.", - task: "Crie uma IIFE.", - hint: "(() => { })()", + title: ' IIFE - Immediately Invoked Function', + level: 'medium', + content: + 'IIFE é uma função que executa imediatamente. ' + + 'Útil para criar escopo privado.', + task: 'Crie uma IIFE.', + hint: '(() => { })()', starterCode: `(function() { const privateVar = "I'm private" console.log("IIFE executed:", privateVar) @@ -5011,13 +5026,13 @@ console.log("Counter:", counter.get())`, }, { id: 138, - title: " Callback Functions", - level: "medium", + title: ' Callback Functions', + level: 'medium', content: - "Callbacks são funções passadas como argumento para outras funções. " + - "Comumente usados em event listeners e array methods.", - task: "Passe uma função como callback.", - hint: "arr.forEach((item) => { })", + 'Callbacks são funções passadas como argumento para outras funções. ' + + 'Comumente usados em event listeners e array methods.', + task: 'Passe uma função como callback.', + hint: 'arr.forEach((item) => { })', starterCode: `function processArray( arr: number[], callback: (n: number) => number @@ -5051,12 +5066,13 @@ withCallback("Alice", (err, result) => { }, { id: 139, - title: " for...in e for...of", - level: "medium", + title: ' for...in e for...of', + level: 'medium', content: - "for...in itera sobre chaves de objetos. " + "for...of itera sobre valores de iteráveis.", - task: "Itere sobre objetos e arrays.", - hint: "for...of para arrays", + 'for...in itera sobre chaves de objetos. ' + + 'for...of itera sobre valores de iteráveis.', + task: 'Itere sobre objetos e arrays.', + hint: 'for...of para arrays', starterCode: `const user = { name: "Alice", age: 25, city: "SP" } console.log("for...in:") @@ -5078,13 +5094,13 @@ for (const [index, num] of numbers.entries()) { }, { id: 140, - title: " while e do...while", - level: "medium", + title: ' while e do...while', + level: 'medium', content: - "while executa enquanto a condição for verdadeira. " + - "do...while executa pelo menos uma vez.", - task: "Use loops while.", - hint: "while (condition) { }", + 'while executa enquanto a condição for verdadeira. ' + + 'do...while executa pelo menos uma vez.', + task: 'Use loops while.', + hint: 'while (condition) { }', starterCode: `let count = 0 while (count < 5) { @@ -5114,11 +5130,13 @@ console.log("Length:", chars)`, }, { id: 141, - title: " break e continue", - level: "medium", - content: "break sai do loop completamente. " + "continue pula para a próxima iteração.", - task: "Controle o fluxo de loops.", - hint: "break para sair, continue para pular", + title: ' break e continue', + level: 'medium', + content: + 'break sai do loop completamente. ' + + 'continue pula para a próxima iteração.', + task: 'Controle o fluxo de loops.', + hint: 'break para sair, continue para pular', starterCode: `for (let i = 1; i <= 10; i++) { if (i === 5) break console.log("i:", i) @@ -5144,11 +5162,13 @@ console.log("Found:", found)`, }, { id: 142, - title: " Labeled Statements", - level: "medium", - content: "Labels identificam loops para break/continue. " + "Útil para loops aninhados.", - task: "Use labels para controlar loops aninhados.", - hint: "label: for (...)", + title: ' Labeled Statements', + level: 'medium', + content: + 'Labels identificam loops para break/continue. ' + + 'Útil para loops aninhados.', + task: 'Use labels para controlar loops aninhados.', + hint: 'label: for (...)', starterCode: `outer: for (let i = 1; i <= 3; i++) { for (let j = 1; j <= 3; j++) { console.log(\`i=\${i}, j=\${j}\`) @@ -5172,10 +5192,12 @@ outer2: while (i < 3) { }, { id: 143, - title: " typeof operator", - level: "medium", - content: "typeof retorna o tipo de um valor como string. " + "Útil para type guards básicos.", - task: "Use typeof para verificar tipos.", + title: ' typeof operator', + level: 'medium', + content: + 'typeof retorna o tipo de um valor como string. ' + + 'Útil para type guards básicos.', + task: 'Use typeof para verificar tipos.', hint: "typeof value === 'string'", starterCode: `console.log("typeof 'hello':", typeof "hello") console.log("typeof 42:", typeof 42) @@ -5198,13 +5220,13 @@ console.log(process(42))`, }, { id: 144, - title: " instanceof", - level: "medium", + title: ' instanceof', + level: 'medium', content: - "instanceof verifica se um objeto é instância de uma classe. " + - "Também funciona para objetos built-in como Array, Date.", - task: "Use instanceof para verificar classes.", - hint: "value instanceof Array", + 'instanceof verifica se um objeto é instância de uma classe. ' + + 'Também funciona para objetos built-in como Array, Date.', + task: 'Use instanceof para verificar classes.', + hint: 'value instanceof Array', starterCode: `class Dog { bark() { return "Woof!" } } @@ -5235,12 +5257,12 @@ process([1, 2, 3])`, }, { id: 145, - title: " in operator", - level: "medium", + title: ' in operator', + level: 'medium', content: - "in verifica se uma propriedade existe em um objeto. " + - "Retorna true para próprias e herdadas (com hasOwnProperty para só próprias).", - task: "Use in para verificar propriedades.", + 'in verifica se uma propriedade existe em um objeto. ' + + 'Retorna true para próprias e herdadas (com hasOwnProperty para só próprias).', + task: 'Use in para verificar propriedades.', hint: "'prop' in object", starterCode: `const user = { name: "Alice", age: 25 } @@ -5269,11 +5291,13 @@ console.log(hasProp(car, "year"))`, }, { id: 146, - title: " delete operator", - level: "medium", - content: "delete remove propriedades de objetos. " + "Não funciona em variáveis ou funções.", - task: "Remova propriedades de objetos.", - hint: "delete object.property", + title: ' delete operator', + level: 'medium', + content: + 'delete remove propriedades de objetos. ' + + 'Não funciona em variáveis ou funções.', + task: 'Remova propriedades de objetos.', + hint: 'delete object.property', starterCode: `const user = { name: "Alice", age: 25, city: "SP" } console.log("Before delete:", user) @@ -5291,13 +5315,13 @@ console.log("'2' in arr:", "2" in arr)`, }, { id: 147, - title: " void operator", - level: "medium", + title: ' void operator', + level: 'medium', content: - "void avalia uma expressão e retorna undefined. " + - "Útil para IIFEs ou previnir navegação em links.", - task: "Use void operator.", - hint: "void expression", + 'void avalia uma expressão e retorna undefined. ' + + 'Útil para IIFEs ou previnir navegação em links.', + task: 'Use void operator.', + hint: 'void expression', starterCode: `console.log("void 0:", void 0) console.log("void 1+1:", void 1 + 1) @@ -5317,13 +5341,13 @@ console.log("Use void for preventDefault")`, }, { id: 148, - title: " Comma Operator", - level: "medium", + title: ' Comma Operator', + level: 'medium', content: - "A vírgula avalia expressões da esquerda para direita e retorna a última. " + - "Útil em loops for e expressões compactas.", - task: "Use operador vírgula.", - hint: "(a, b, c) - retorna c", + 'A vírgula avalia expressões da esquerda para direita e retorna a última. ' + + 'Útil em loops for e expressões compactas.', + task: 'Use operador vírgula.', + hint: '(a, b, c) - retorna c', starterCode: `const result = (1, 2, 3) console.log("Result:", result) @@ -5341,13 +5365,13 @@ console.log("Coords:", coords)`, }, { id: 149, - title: " Bitwise Operators", - level: "medium", + title: ' Bitwise Operators', + level: 'medium', content: - "Operadores bitwise manipulam bits de números. " + - "Útil para flags, criptografia, otimização.", - task: "Use operadores bitwise.", - hint: "& | ^ ~ << >>", + 'Operadores bitwise manipulam bits de números. ' + + 'Útil para flags, criptografia, otimização.', + task: 'Use operadores bitwise.', + hint: '& | ^ ~ << >>', starterCode: `console.log("5 & 3:", 5 & 3) console.log("5 | 3:", 5 | 3) console.log("5 ^ 3:", 5 ^ 3) @@ -5374,12 +5398,12 @@ console.log("After removing A:", flags)`, }, { id: 150, - title: " eval", - level: "medium", + title: ' eval', + level: 'medium', content: - "eval executa uma string como código JavaScript. " + - "Evite usar em código de produção por segurança.", - task: "Use eval com cuidado.", + 'eval executa uma string como código JavaScript. ' + + 'Evite usar em código de produção por segurança.', + task: 'Use eval com cuidado.', hint: "eval('code string')", starterCode: `const code = "2 + 2" console.log("Result:", eval(code)) From 074c0942e2c52f0cb1f27bb7a913a89dbee08361 Mon Sep 17 00:00:00 2001 From: Mostafa Date: Fri, 17 Jul 2026 08:58:55 +0300 Subject: [PATCH 3/4] revert unnecessery changes --- src/data/lessons/lessons-en.ts | 1746 +++++++++++++++---------------- src/data/lessons/lessons.ts | 1774 ++++++++++++++++---------------- 2 files changed, 1733 insertions(+), 1787 deletions(-) diff --git a/src/data/lessons/lessons-en.ts b/src/data/lessons/lessons-en.ts index a2ceef7..0e6b7e5 100644 --- a/src/data/lessons/lessons-en.ts +++ b/src/data/lessons/lessons-en.ts @@ -1,17 +1,17 @@ -import type { Lesson } from './types'; +import type { Lesson } from "./types"; export const lessonsEn: Lesson[] = [ { id: 1, - title: 'Welcome to TypeScript', - level: 'basic', + title: "Welcome to TypeScript", + level: "basic", content: - 'TypeScript is a superset of JavaScript that adds static typing. ' + + "TypeScript is a superset of JavaScript that adds static typing. " + 'With it, you define the "shape" of your data using interfaces, preventing ' + - 'runtime errors. See the example: we create a `User` interface with ' + - 'two typed fields and instantiate an object that follows it.', + "runtime errors. See the example: we create a `User` interface with " + + "two typed fields and instantiate an object that follows it.", task: "Try changing the user's name in the editor and click Compile & Run.", - hint: 'Change the value of `name` inside the `user` object.', + hint: "Change the value of `name` inside the `user` object.", starterCode: `interface User { name: string; id: number; @@ -26,14 +26,14 @@ console.log(\`Hello, \${user.name}! Your ID is \${user.id}.\`);`, }, { id: 2, - title: 'Static Typing and Inference', - level: 'basic', - content: - 'TypeScript automatically infers types in many cases. When you define a variable ' + - 'with an initial value, TypeScript deduces its type. This is called type inference and ' + - 'makes the code more concise while maintaining safety.', - task: 'Observe how TypeScript infers the type of the `message` variable.', - hint: 'The type is inferred from the initial value.', + title: "Static Typing and Inference", + level: "basic", + content: + "TypeScript automatically infers types in many cases. When you define a variable " + + "with an initial value, TypeScript deduces its type. This is called type inference and " + + "makes the code more concise while maintaining safety.", + task: "Observe how TypeScript infers the type of the `message` variable.", + hint: "The type is inferred from the initial value.", starterCode: `let message = "Hello, TypeScript!" let count = 42 let isActive = true @@ -49,13 +49,13 @@ console.log(isActive)`, }, { id: 3, - title: 'Interfaces', - level: 'basic', + title: "Interfaces", + level: "basic", content: - 'Interfaces define the structure that objects must follow. They are fundamental in TypeScript ' + - 'to ensure objects have the correct properties with the right types.', - task: 'Add an `email` property to the `Person` interface and the object.', - hint: 'Add `email: string` to the interface.', + "Interfaces define the structure that objects must follow. They are fundamental in TypeScript " + + "to ensure objects have the correct properties with the right types.", + task: "Add an `email` property to the `Person` interface and the object.", + hint: "Add `email: string` to the interface.", starterCode: `interface Person { name: string age: number @@ -70,13 +70,13 @@ console.log(\`\${person.name} is \${person.age} years old\`)`, }, { id: 4, - title: 'Enums', - level: 'basic', + title: "Enums", + level: "basic", content: - 'Enums allow you to define a set of named constants. They are useful for ' + - 'representing states, directions, user roles, etc. TypeScript supports ' + - 'numeric (default) and string enums.', - task: 'Add an `ADMIN` value to the `Role` enum and create a user with that role.', + "Enums allow you to define a set of named constants. They are useful for " + + "representing states, directions, user roles, etc. TypeScript supports " + + "numeric (default) and string enums.", + task: "Add an `ADMIN` value to the `Role` enum and create a user with that role.", hint: 'Add `ADMIN = "ADMIN"` to the enum and use `Role.ADMIN` in the object.', starterCode: `enum Direction { UP = "UP", @@ -106,14 +106,14 @@ console.log(\`\${player.name} (\${player.role}) is facing \${player.facing}\`)`, }, { id: 5, - title: 'Type Aliases and Union Types', - level: 'basic', - content: - 'Type aliases create names for complex types. Union types (`|`) allow ' + - 'a variable to accept more than one type. This is much safer than using ' + - '`any` while maintaining flexibility.', - task: 'Create a type alias `Result` that is `string | number | boolean`.', - hint: 'type Result = string | number | boolean;', + title: "Type Aliases and Union Types", + level: "basic", + content: + "Type aliases create names for complex types. Union types (`|`) allow " + + "a variable to accept more than one type. This is much safer than using " + + "`any` while maintaining flexibility.", + task: "Create a type alias `Result` that is `string | number | boolean`.", + hint: "type Result = string | number | boolean;", starterCode: `type ID = string | number type Status = "active" | "inactive" | "pending" @@ -136,14 +136,14 @@ console.log(getStatusLabel("active"))`, }, { id: 6, - title: 'Type Assertions', - level: 'basic', + title: "Type Assertions", + level: "basic", content: - 'Type assertions tell TypeScript to treat a value as a specific type. ' + + "Type assertions tell TypeScript to treat a value as a specific type. " + 'Use `as` or angle bracket syntax. It\'s like a "cast" in other languages, ' + "but doesn't convert the value at runtime.", - task: 'Use type assertion to treat `input` as `string`.', - hint: 'const str = input as string;', + task: "Use type assertion to treat `input` as `string`.", + hint: "const str = input as string;", starterCode: `let input: unknown = "hello world" const length1 = (input as string).length @@ -154,15 +154,15 @@ console.log("Length 2:", length2)`, }, { id: 7, - title: 'Basic Types', - level: 'basic', + title: "Basic Types", + level: "basic", content: - 'TypeScript supports all JavaScript primitive types: `string`, `number`, ' + - '`boolean`, `null`, `undefined`. It also offers `symbol`, `bigint` and the ' + + "TypeScript supports all JavaScript primitive types: `string`, `number`, " + + "`boolean`, `null`, `undefined`. It also offers `symbol`, `bigint` and the " + "type `void` for functions that don't return anything.", - task: 'Create variables of the types you learned.', + task: "Create variables of the types you learned.", hint: 'let name: string = "Alice";', - starterCode: `{let name: string = "Alice" + starterCode: `let name: string = "Alice" let age: number = 25 let isStudent: boolean = true let nothing: null = null @@ -170,15 +170,15 @@ let notDefined: undefined = undefined let id: symbol = Symbol("id") let bigNumber: bigint = 9007199254740991n -console.log(name, age, isStudent)}`, +console.log(name, age, isStudent)`, }, { id: 8, - title: 'Arrays and Tuples', - level: 'basic', + title: "Arrays and Tuples", + level: "basic", content: - 'Arrays in TypeScript can be typed as `number[]` or `Array`. ' + - 'Tuples are arrays with a fixed size and specific types at each position: `[string, number]`.', + "Arrays in TypeScript can be typed as `number[]` or `Array`. " + + "Tuples are arrays with a fixed size and specific types at each position: `[string, number]`.", task: "Create a tuple with a person's name and age.", hint: 'let person: [string, number] = ["Alice", 25];', starterCode: `const numbers: number[] = [1, 2, 3, 4, 5] @@ -193,13 +193,13 @@ console.log("Coords:", coords)`, }, { id: 9, - title: 'Functions - Parameter and Return Typing', - level: 'basic', + title: "Functions - Parameter and Return Typing", + level: "basic", content: - 'Functions in TypeScript can have defined types for parameters and return. ' + - 'This ensures the function is called with the correct arguments and returns the expected value.', - task: 'Add the return type `number` to the `soma` function.', - hint: 'function soma(a: number, b: number): number', + "Functions in TypeScript can have defined types for parameters and return. " + + "This ensures the function is called with the correct arguments and returns the expected value.", + task: "Add the return type `number` to the `soma` function.", + hint: "function soma(a: number, b: number): number", starterCode: `function greet(name: string): string { return \`Hello, \${name}!\` } @@ -216,14 +216,14 @@ console.log(add(10, 20))`, }, { id: 10, - title: 'Optional and Default Parameters', - level: 'basic', - content: - 'Optional parameters use `?` (e.g., `name?: string`). Parameters with default values ' + - 'are automatically optional. The difference is that `undefined` is passed for optionals, ' + - 'while the default value is used for parameters with defaults.', - task: 'Make the `age` parameter optional in the `introduce` function.', - hint: 'function introduce(name: string, age?: number)', + title: "Optional and Default Parameters", + level: "basic", + content: + "Optional parameters use `?` (e.g., `name?: string`). Parameters with default values " + + "are automatically optional. The difference is that `undefined` is passed for optionals, " + + "while the default value is used for parameters with defaults.", + task: "Make the `age` parameter optional in the `introduce` function.", + hint: "function introduce(name: string, age?: number)", starterCode: `function greet(name: string, greeting?: string): string { return greeting ? \`\${greeting}, \${name}!\` : \`Hello, \${name}!\` } @@ -242,12 +242,12 @@ console.log(introduce("Diana"))`, }, { id: 11, - title: 'Utility Types - Partial, Required, Pick, Omit', - level: 'basic', + title: "Utility Types - Partial, Required, Pick, Omit", + level: "basic", content: - 'TypeScript includes built-in utility types that transform existing types: ' + - '`Partial` makes all fields optional, `Required` makes them required, ' + - '`Pick` selects fields, `Omit` removes fields.', + "TypeScript includes built-in utility types that transform existing types: " + + "`Partial` makes all fields optional, `Required` makes them required, " + + "`Pick` selects fields, `Omit` removes fields.", task: 'Use `Omit` to create a `PublicUser` type.', hint: 'type PublicUser = Omit', starterCode: `interface User { @@ -275,14 +275,14 @@ console.log("Preview:", JSON.stringify(preview))`, }, { id: 12, - title: 'Mapped Types', - level: 'basic', - content: - 'Mapped types allow you to create new types by transforming each property of an existing type. ' + - 'They use the syntax `{ [K in keyof T]: ... }`. Combined with `keyof` and modifiers ' + - '(`readonly`, `?`), they are extremely powerful.', - task: 'Create a mapped type `Nullable` that makes all properties optional.', - hint: 'type Nullable = { [K in keyof T]?: T[K] | null; }', + title: "Mapped Types", + level: "basic", + content: + "Mapped types allow you to create new types by transforming each property of an existing type. " + + "They use the syntax `{ [K in keyof T]: ... }`. Combined with `keyof` and modifiers " + + "(`readonly`, `?`), they are extremely powerful.", + task: "Create a mapped type `Nullable` that makes all properties optional.", + hint: "type Nullable = { [K in keyof T]?: T[K] | null; }", starterCode: `interface Config { host: string port: number @@ -308,14 +308,14 @@ console.log("Partial:", JSON.stringify(partial))`, }, { id: 13, - title: 'Conditional Types', - level: 'basic', - content: - 'Conditional types follow the syntax `T extends U ? X : Y` — if `T` is assignable to `U`, ' + - 'the resulting type is `X`, otherwise `Y`. With `infer`, you can extract types ' + - 'from inside other types.', - task: 'Create a conditional type `IsArray` that returns `true` if T is an array.', - hint: 'type IsArray = T extends any[] ? true : false', + title: "Conditional Types", + level: "basic", + content: + "Conditional types follow the syntax `T extends U ? X : Y` — if `T` is assignable to `U`, " + + "the resulting type is `X`, otherwise `Y`. With `infer`, you can extract types " + + "from inside other types.", + task: "Create a conditional type `IsArray` that returns `true` if T is an array.", + hint: "type IsArray = T extends any[] ? true : false", starterCode: `type IsString = T extends string ? "yes" : "no" type A = IsString @@ -339,14 +339,14 @@ console.log("Result:", JSON.stringify(result))`, }, { id: 14, - title: 'Decorators', - level: 'basic', - content: - 'Decorators are special functions that can be applied to classes, methods, ' + - 'properties and parameters using the `@decorator` syntax. They are widely used ' + - 'in frameworks like Angular, NestJS and TypeORM.', - task: 'Create a `@readonly` decorator that makes a property non-editable.', - hint: 'Use Object.defineProperty in the descriptor.', + title: "Decorators", + level: "basic", + content: + "Decorators are special functions that can be applied to classes, methods, " + + "properties and parameters using the `@decorator` syntax. They are widely used " + + "in frameworks like Angular, NestJS and TypeORM.", + task: "Create a `@readonly` decorator that makes a property non-editable.", + hint: "Use Object.defineProperty in the descriptor.", starterCode: `function sealed(constructor: Function) { Object.seal(constructor) Object.seal(constructor.prototype) @@ -380,14 +380,14 @@ console.log("Fib(10):", calc.fibonacci(10))`, }, { id: 15, - title: 'Generics - Introduction', - level: 'basic', - content: - 'Generics allow you to create components that work with any type while maintaining ' + - 'type safety. They are represented by `` and allow you to create reusable ' + - 'functions, classes and interfaces.', - task: 'Create an `identity` function that returns the same value passed.', - hint: 'function identity(value: T): T { return value; }', + title: "Generics - Introduction", + level: "basic", + content: + "Generics allow you to create components that work with any type while maintaining " + + "type safety. They are represented by `` and allow you to create reusable " + + "functions, classes and interfaces.", + task: "Create an `identity` function that returns the same value passed.", + hint: "function identity(value: T): T { return value; }", starterCode: `function identity(value: T): T { return value } @@ -400,11 +400,11 @@ console.log(str, num, auto)`, }, { id: 16, - title: 'Literal Types', - level: 'basic', + title: "Literal Types", + level: "basic", content: - 'TypeScript allows you to specify exact values a variable can have using literal types. ' + - 'This is useful when you want to restrict a value to a specific set of strings or numbers.', + "TypeScript allows you to specify exact values a variable can have using literal types. " + + "This is useful when you want to restrict a value to a specific set of strings or numbers.", task: "Create a variable that can only have the values 'pending', 'loading' or 'success'.", hint: "type Status = 'pending' | 'loading' | 'success';", starterCode: `type Status = "pending" | "loading" | "success" @@ -416,13 +416,13 @@ console.log("Current status:", currentStatus)`, }, { id: 17, - title: 'Function Overloads', - level: 'basic', + title: "Function Overloads", + level: "basic", content: - 'TypeScript supports function overloading, allowing you to define multiple signatures. ' + - 'TypeScript chooses the correct signature based on the arguments provided.', - task: 'Create a `format` function that can format numbers and dates.', - hint: 'Use multiple signatures before the implementation.', + "TypeScript supports function overloading, allowing you to define multiple signatures. " + + "TypeScript chooses the correct signature based on the arguments provided.", + task: "Create a `format` function that can format numbers and dates.", + hint: "Use multiple signatures before the implementation.", starterCode: `function format(value: string): string function format(value: number, decimals?: number): string function format(value: Date): string @@ -445,13 +445,13 @@ console.log(format(new Date()))`, }, { id: 18, - title: 'Modules and Imports/Exports', - level: 'basic', + title: "Modules and Imports/Exports", + level: "basic", content: - 'TypeScript has full support for the ES6 module system. Organize your code in separate files ' + - 'with explicit imports and exports for better encapsulation.', - task: 'Create and export a function from a module, and import it in another.', - hint: 'Use `export` and `import` in ES6 style.', + "TypeScript has full support for the ES6 module system. Organize your code in separate files " + + "with explicit imports and exports for better encapsulation.", + task: "Create and export a function from a module, and import it in another.", + hint: "Use `export` and `import` in ES6 style.", starterCode: `export const capitalize = (str: string): string => { return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase() } @@ -471,13 +471,13 @@ console.log(trim(text))`, }, { id: 19, - title: 'Namespaces', - level: 'basic', + title: "Namespaces", + level: "basic", content: - 'Namespaces group related code without polluting the global scope. Use `namespace` ' + - 'to organize code internally and `export` to expose members.', - task: 'Create a `MathUtils` namespace with `add` and `multiply` functions.', - hint: 'namespace MathUtils { export function add(...) }', + "Namespaces group related code without polluting the global scope. Use `namespace` " + + "to organize code internally and `export` to expose members.", + task: "Create a `MathUtils` namespace with `add` and `multiply` functions.", + hint: "namespace MathUtils { export function add(...) }", starterCode: `namespace MathUtils { export function add(a: number, b: number): number { return a + b @@ -496,13 +496,13 @@ console.log("PI:", MathUtils.PI)`, }, { id: 20, - title: 'Iterators and Generators', - level: 'basic', + title: "Iterators and Generators", + level: "basic", content: - 'TypeScript has full support for ES6 iterator and generator protocols. ' + - 'Generators (`function*`) provide an easy way to create functions that return sequences.', - task: 'Create a generator function that yields numbers from 1 to N.', - hint: 'Use function* and yield.', + "TypeScript has full support for ES6 iterator and generator protocols. " + + "Generators (`function*`) provide an easy way to create functions that return sequences.", + task: "Create a generator function that yields numbers from 1 to N.", + hint: "Use function* and yield.", starterCode: `function* counter(limit: number) { let count = 1 while (count <= limit) { @@ -521,13 +521,13 @@ console.log("As array:", nums)`, }, { id: 21, - title: 'Advanced Type Inference', - level: 'advanced', + title: "Advanced Type Inference", + level: "advanced", content: - 'TypeScript automatically infers types in many contexts. Inference works ' + - 'in variables, parameters, returns and uses control flow analysis and contextual typing.', - task: 'Observe how TypeScript infers different types in the same example.', - hint: 'Return type changes based on the parameter.', + "TypeScript automatically infers types in many contexts. Inference works " + + "in variables, parameters, returns and uses control flow analysis and contextual typing.", + task: "Observe how TypeScript infers different types in the same example.", + hint: "Return type changes based on the parameter.", starterCode: `function processInput(input: string | number) { if (typeof input === "string") { return input.toUpperCase() @@ -547,13 +547,13 @@ console.log("Doubled:", doubled)`, }, { id: 22, - title: 'Structural Type Compatibility', - level: 'advanced', + title: "Structural Type Compatibility", + level: "advanced", content: - 'TypeScript uses structural compatibility — two types are compatible if they have the same structure. ' + - 'This is different from nominal systems and makes TypeScript more flexible.', - task: 'See how objects with compatible structures can be used interchangeably.', - hint: 'If properties match, the type is compatible.', + "TypeScript uses structural compatibility — two types are compatible if they have the same structure. " + + "This is different from nominal systems and makes TypeScript more flexible.", + task: "See how objects with compatible structures can be used interchangeably.", + hint: "If properties match, the type is compatible.", starterCode: `interface Point { x: number y: number @@ -578,13 +578,13 @@ console.log("Distance:", distanceFromOrigin(namedPoint))`, }, { id: 23, - title: 'Working with JavaScript', - level: 'basic', + title: "Working with JavaScript", + level: "basic", content: - 'TypeScript was designed to gradually adopt existing JavaScript. ' + - 'Use `@ts-check` or `checkJs: true` in tsconfig.json to check .js files.', - task: 'Understand how TypeScript checks JavaScript code.', - hint: 'Use JSDoc to add types in .js files.', + "TypeScript was designed to gradually adopt existing JavaScript. " + + "Use `@ts-check` or `checkJs: true` in tsconfig.json to check .js files.", + task: "Understand how TypeScript checks JavaScript code.", + hint: "Use JSDoc to add types in .js files.", starterCode: `// Simulating .js file verification // To enable: use // @ts-check at the top @@ -610,13 +610,13 @@ console.log("Factorial of 5:", factorial(5))`, }, { id: 24, - title: 'Declaration Files (.d.ts)', - level: 'advanced', + title: "Declaration Files (.d.ts)", + level: "advanced", content: - 'Declaration files (.d.ts) provide type information for JavaScript libraries. ' + - 'Type definitions for popular libraries are in DefinitelyTyped (@types/*).', - task: 'Create a simple declaration file for a function.', - hint: 'declare function name(params): returnType;', + "Declaration files (.d.ts) provide type information for JavaScript libraries. " + + "Type definitions for popular libraries are in DefinitelyTyped (@types/*).", + task: "Create a simple declaration file for a function.", + hint: "declare function name(params): returnType;", starterCode: `// Simulating a declaration file declare namespace Utils { @@ -642,12 +642,12 @@ console.log("Install types: npm install @types/lodash")`, }, { id: 25, - title: 'Classes - Introduction', - level: 'basic', + title: "Classes - Introduction", + level: "basic", content: - 'Classes in TypeScript work like modern JavaScript but with full typing. ' + - 'You can define properties, methods, constructors and access modifiers.', - task: 'Add a `sayHello` method to the `Person` class.', + "Classes in TypeScript work like modern JavaScript but with full typing. " + + "You can define properties, methods, constructors and access modifiers.", + task: "Add a `sayHello` method to the `Person` class.", hint: "sayHello() { return 'Hello, ' + this.name; }", starterCode: `class Person { name: string @@ -668,13 +668,13 @@ console.log(person.greet())`, }, { id: 26, - title: 'Access Modifiers', - level: 'basic', + title: "Access Modifiers", + level: "basic", content: - 'TypeScript offers `public`, `private` and `protected` to control access to members. ' + - 'There is also `readonly` for properties that cannot be changed after initialization.', - task: 'Make the `balance` property private and add a getter.', - hint: 'private balance: number; public getBalance()', + "TypeScript offers `public`, `private` and `protected` to control access to members. " + + "There is also `readonly` for properties that cannot be changed after initialization.", + task: "Make the `balance` property private and add a getter.", + hint: "private balance: number; public getBalance()", starterCode: `class BankAccount { public readonly id: number private balance: number @@ -705,13 +705,13 @@ console.log("New Balance:", account.getBalance())`, }, { id: 27, - title: 'Class Inheritance', - level: 'basic', + title: "Class Inheritance", + level: "basic", content: - 'Classes can inherit from other classes using `extends`. The child class has access to ' + - 'public/protected methods and properties from the parent class and can override them.', - task: 'Create a `Student` class that inherits from `Person`.', - hint: 'class Student extends Person { }', + "Classes can inherit from other classes using `extends`. The child class has access to " + + "public/protected methods and properties from the parent class and can override them.", + task: "Create a `Student` class that inherits from `Person`.", + hint: "class Student extends Person { }", starterCode: `class Person { constructor(public name: string, public age: number) {} @@ -736,13 +736,13 @@ console.log(student.study())`, }, { id: 28, - title: 'Abstract Classes', - level: 'basic', + title: "Abstract Classes", + level: "basic", content: - 'Abstract classes cannot be instantiated directly, they serve as base for other classes. ' + - 'They can contain abstract methods (without implementation) that child classes must implement.', - task: 'Create an abstract `Shape` class with abstract `area` method.', - hint: 'abstract class Shape { abstract area(): number; }', + "Abstract classes cannot be instantiated directly, they serve as base for other classes. " + + "They can contain abstract methods (without implementation) that child classes must implement.", + task: "Create an abstract `Shape` class with abstract `area` method.", + hint: "abstract class Shape { abstract area(): number; }", starterCode: `abstract class Shape { abstract area(): number abstract perimeter(): number @@ -788,12 +788,12 @@ console.log(circle.describe())`, }, { id: 29, - title: 'Getters and Setters', - level: 'basic', + title: "Getters and Setters", + level: "basic", content: - 'Getters and setters allow precise control over property access. ' + - 'Useful for validation, computed values, or maintaining class invariants.', - task: 'Create a `fullName` getter that returns the full name.', + "Getters and setters allow precise control over property access. " + + "Useful for validation, computed values, or maintaining class invariants.", + task: "Create a `fullName` getter that returns the full name.", hint: "get fullName(): string { return this.firstName + ' ' + this.lastName; }", starterCode: `class User { private _password: string = "" @@ -827,13 +827,13 @@ console.log("Password:", user.password)`, }, { id: 30, - title: 'Static Members', - level: 'basic', + title: "Static Members", + level: "basic", content: - 'Static members belong to the class itself, not to instances. ' + - 'Accessed via `ClassName.property`, they are useful for constants or utility functions.', - task: 'Add a static `createDefault` method to the `User` class.', - hint: 'static createDefault(): User { }', + "Static members belong to the class itself, not to instances. " + + "Accessed via `ClassName.property`, they are useful for constants or utility functions.", + task: "Add a static `createDefault` method to the `User` class.", + hint: "static createDefault(): User { }", starterCode: `class MathHelper { static readonly PI = 3.14159 @@ -853,14 +853,14 @@ console.log("Factorial 5:", MathHelper.factorial(5))`, }, { id: 31, - title: 'Utility Types - Record, Partial, Readonly', - level: 'advanced', - content: - '`Record` creates an object type with keys K and values V. ' + - '`Partial` makes all properties optional. ' + - '`Readonly` makes all properties read-only.', - task: 'Create a `UserRecord` type using Record.', - hint: 'type UserRecord = Record', + title: "Utility Types - Record, Partial, Readonly", + level: "advanced", + content: + "`Record` creates an object type with keys K and values V. " + + "`Partial` makes all properties optional. " + + "`Readonly` makes all properties read-only.", + task: "Create a `UserRecord` type using Record.", + hint: "type UserRecord = Record", starterCode: `interface User { id: number name: string @@ -884,13 +884,13 @@ console.log("Partial:", JSON.stringify(partial))`, }, { id: 32, - title: 'Utility Types - Extract and Exclude', - level: 'advanced', + title: "Utility Types - Extract and Exclude", + level: "advanced", content: - '`Extract` extracts from T the types that are assignable to U. ' + - '`Exclude` removes from T the types that are assignable to U.', - task: 'Use Extract to get only strings from a union type.', - hint: 'type Strings = Extract', + "`Extract` extracts from T the types that are assignable to U. " + + "`Exclude` removes from T the types that are assignable to U.", + task: "Use Extract to get only strings from a union type.", + hint: "type Strings = Extract", starterCode: `type T = string | number | boolean | null type Strings = Extract @@ -907,13 +907,13 @@ console.log("NotNull:", bool)`, }, { id: 33, - title: 'Utility Types - ReturnType and Parameters', - level: 'advanced', + title: "Utility Types - ReturnType and Parameters", + level: "advanced", content: - '`ReturnType` gets the return type of a function. ' + - '`Parameters` gets the parameter types as a tuple.', - task: 'Get the return type and parameters of a function.', - hint: 'type R = ReturnType', + "`ReturnType` gets the return type of a function. " + + "`Parameters` gets the parameter types as a tuple.", + task: "Get the return type and parameters of a function.", + hint: "type R = ReturnType", starterCode: `function createUser(name: string, age: number): { name: string; age: number; id: number } { return { name, age, id: Math.random() } } @@ -929,13 +929,13 @@ console.log("Args:", args)`, }, { id: 34, - title: 'Type Guards', - level: 'basic', + title: "Type Guards", + level: "basic", content: - 'Type guards are expressions that refine the type of a variable. ' + - 'Use `typeof`, `instanceof`, or custom with `is` to filter types in unions.', - task: 'Create a type guard to check if a value is a string.', - hint: 'function isString(value: unknown): value is string { }', + "Type guards are expressions that refine the type of a variable. " + + "Use `typeof`, `instanceof`, or custom with `is` to filter types in unions.", + task: "Create a type guard to check if a value is a string.", + hint: "function isString(value: unknown): value is string { }", starterCode: `function isString(value: unknown): value is string { return typeof value === "string" } @@ -969,13 +969,13 @@ if (isDog(pet)) { }, { id: 35, - title: 'unknown and any', - level: 'basic', + title: "unknown and any", + level: "basic", content: - '`any` completely disables type checking. ' + + "`any` completely disables type checking. " + '`unknown` is the "safe" type that represents any value — you must refine it before using.', - task: 'Refine an `unknown` type to use it safely.', - hint: 'Use type guards to check the type.', + task: "Refine an `unknown` type to use it safely.", + hint: "Use type guards to check the type.", starterCode: `let anyValue: any = "hello" let unknownValue: unknown = "world" @@ -992,13 +992,13 @@ console.log(str)`, }, { id: 36, - title: 'never', - level: 'basic', + title: "never", + level: "basic", content: - '`never` represents values that never occur. Functions that always throw errors ' + - 'or infinite loops have return type `never`. It is also used in exhaustive unions.', - task: 'Create a function that throws an error and has return type never.', - hint: 'function error(): never { throw new Error(); }', + "`never` represents values that never occur. Functions that always throw errors " + + "or infinite loops have return type `never`. It is also used in exhaustive unions.", + task: "Create a function that throws an error and has return type never.", + hint: "function error(): never { throw new Error(); }", starterCode: `function throwError(message: string): never { throw new Error(message) } @@ -1029,11 +1029,11 @@ console.log("Declaration merging works!")`, }, { id: 37, - title: 'keyof and Index Access Types', - level: 'advanced', + title: "keyof and Index Access Types", + level: "advanced", content: - '`keyof` gets the keys of a type as a union. ' + - 'Use `T[K]` to access the type of a specific property.', + "`keyof` gets the keys of a type as a union. " + + "Use `T[K]` to access the type of a specific property.", task: "Get the keys of User and the type of the 'name' property.", hint: 'type Keys = keyof User; type NameType = User["name"]', starterCode: `interface User { @@ -1058,13 +1058,13 @@ console.log(getProperty(user, "email"))`, }, { id: 38, - title: 'Generic Constraints', - level: 'basic', + title: "Generic Constraints", + level: "basic", content: - 'Constraints use `extends` to limit the types that can be used with generics. ' + - 'This ensures the type has the necessary properties.', - task: 'Create a generic that only accepts objects with a `length` property.', - hint: 'function fn(arg: T)', + "Constraints use `extends` to limit the types that can be used with generics. " + + "This ensures the type has the necessary properties.", + task: "Create a generic that only accepts objects with a `length` property.", + hint: "function fn(arg: T)", starterCode: `function getLength(arg: T): number { return arg.length } @@ -1082,13 +1082,13 @@ console.log("Merged:", JSON.stringify(result))`, }, { id: 39, - title: 'Generic Classes', - level: 'basic', + title: "Generic Classes", + level: "basic", content: - 'Generic classes allow creating reusable components that work with different types. ' + - 'The type is specified when creating an instance of the class.', - task: 'Create a class `Box` that stores a value.', - hint: 'class Box { private content: T; }', + "Generic classes allow creating reusable components that work with different types. " + + "The type is specified when creating an instance of the class.", + task: "Create a class `Box` that stores a value.", + hint: "class Box { private content: T; }", starterCode: `class Box { private content: T @@ -1116,13 +1116,13 @@ console.log("Updated:", numberBox.get())`, }, { id: 40, - title: 'Generic Interfaces', - level: 'basic', + title: "Generic Interfaces", + level: "basic", content: - 'Generic interfaces define contracts that work with multiple types. ' + - 'They are the foundation of libraries like React, Zod, and Prisma.', - task: 'Create a `Repository` interface with CRUD methods.', - hint: 'interface Repository { findAll(): T[]; }', + "Generic interfaces define contracts that work with multiple types. " + + "They are the foundation of libraries like React, Zod, and Prisma.", + task: "Create a `Repository` interface with CRUD methods.", + hint: "interface Repository { findAll(): T[]; }", starterCode: `interface Entity { id: number } @@ -1177,13 +1177,13 @@ console.log("Find 1:", repo.findById(1))`, }, { id: 41, - title: 'Error Handling Typing', - level: 'basic', + title: "Error Handling Typing", + level: "basic", content: - 'TypeScript improves error handling with better inference in try/catch blocks. ' + - 'Specify the error type for better autocomplete.', - task: 'Create a function that can throw errors and handle them.', - hint: 'try { } catch (error) { if (error instanceof Error) { } }', + "TypeScript improves error handling with better inference in try/catch blocks. " + + "Specify the error type for better autocomplete.", + task: "Create a function that can throw errors and handle them.", + hint: "try { } catch (error) { if (error instanceof Error) { } }", starterCode: `function divide(a: number, b: number): number { if (b === 0) { throw new Error("Division by zero is not allowed") @@ -1227,13 +1227,13 @@ try { }, { id: 42, - title: 'Async/Await and Promises', - level: 'basic', + title: "Async/Await and Promises", + level: "basic", content: - 'TypeScript fully supports typed async/await. Async functions return Promises, ' + - 'and you can type the resolved value.', - task: 'Create an async function that returns a typed user.', - hint: 'async function fetchUser(): Promise { }', + "TypeScript fully supports typed async/await. Async functions return Promises, " + + "and you can type the resolved value.", + task: "Create an async function that returns a typed user.", + hint: "async function fetchUser(): Promise { }", starterCode: `interface User { id: number name: string @@ -1269,13 +1269,13 @@ main()`, }, { id: 43, - title: 'this in Types', - level: 'basic', + title: "this in Types", + level: "basic", content: - 'TypeScript allows typing `this` in methods. Use `this` as the first parameter ' + - 'to ensure methods are called in the correct context (fluent API).', - task: 'Create a fluent API with methods that return `this`.', - hint: 'add(name: string): this { }', + "TypeScript allows typing `this` in methods. Use `this` as the first parameter " + + "to ensure methods are called in the correct context (fluent API).", + task: "Create a fluent API with methods that return `this`.", + hint: "add(name: string): this { }", starterCode: `class Builder { private parts: string[] = [] @@ -1328,13 +1328,13 @@ console.log("Calc result:", calc.result())`, }, { id: 44, - title: 'Optional Chaining and Nullish Coalescing', - level: 'basic', + title: "Optional Chaining and Nullish Coalescing", + level: "basic", content: - '`?.` accesses deep properties without error if something is null/undefined. ' + - '`??` returns the right operand if the left is null/undefined.', - task: 'Use optional chaining to access a nested property.', - hint: 'user?.address?.city', + "`?.` accesses deep properties without error if something is null/undefined. " + + "`??` returns the right operand if the left is null/undefined.", + task: "Use optional chaining to access a nested property.", + hint: "user?.address?.city", starterCode: `interface User { name: string address?: { @@ -1367,13 +1367,13 @@ console.log("Zero:", zero)`, }, { id: 45, - title: 'Non-null Assertion Operator', - level: 'basic', + title: "Non-null Assertion Operator", + level: "basic", content: - '`!` tells TypeScript that a value is not null/undefined. Use with caution — ' + - 'only when you are sure the value exists.', - task: 'Use non-null assertion to access a guaranteed property.', - hint: 'element!.value', + "`!` tells TypeScript that a value is not null/undefined. Use with caution — " + + "only when you are sure the value exists.", + task: "Use non-null assertion to access a guaranteed property.", + hint: "element!.value", starterCode: `function getElement(): HTMLInputElement | null { return document.createElement("input") } @@ -1391,13 +1391,13 @@ console.log("Result:", result)`, }, { id: 46, - title: 'Type Casting vs Assertion', - level: 'basic', + title: "Type Casting vs Assertion", + level: "basic", content: - 'Type assertions (`as`) convert types. Use them when you know more about the type ' + + "Type assertions (`as`) convert types. Use them when you know more about the type " + "than TypeScript does. Different from casting in other languages, it doesn't convert the value.", - task: 'Use assertion to convert one type to another.', - hint: 'const num = value as number', + task: "Use assertion to convert one type to another.", + hint: "const num = value as number", starterCode: `let input: unknown = "123" const strLength1 = (input as string).length @@ -1429,13 +1429,13 @@ processAnimal(dog)`, }, { id: 47, - title: 'Template Literal Types', - level: 'advanced', + title: "Template Literal Types", + level: "advanced", content: - 'Template literal types create new types using string templates. ' + - 'Combine with infer to extract and manipulate strings in types.', - task: 'Create a type that automatically creates getters.', - hint: 'type Getters = { [K in keyof T as `get${K}`]: () => T[K] }', + "Template literal types create new types using string templates. " + + "Combine with infer to extract and manipulate strings in types.", + task: "Create a type that automatically creates getters.", + hint: "type Getters = { [K in keyof T as `get${K}`]: () => T[K] }", starterCode: `type World = "world" type Greeting = \`hello \${World}\` @@ -1464,12 +1464,12 @@ console.log(getters.getAge())`, }, { id: 48, - title: 'Discriminated Unions', - level: 'basic', + title: "Discriminated Unions", + level: "basic", content: - 'Create unions with a common property (discriminator) to make it easier for TypeScript ' + - 'to identify which union member is in use. Very useful for state management.', - task: 'Create a discriminated union for file formats.', + "Create unions with a common property (discriminator) to make it easier for TypeScript " + + "to identify which union member is in use. Very useful for state management.", + task: "Create a discriminated union for file formats.", hint: 'type File = { type: "image", data: ... } | { type: "video", data: ... }', starterCode: `type Loading = { status: "loading" } type Success = { status: "success"; data: string } @@ -1501,13 +1501,13 @@ handleResult(errorResult)`, }, { id: 49, - title: 'Mixin Classes', - level: 'advanced', + title: "Mixin Classes", + level: "advanced", content: - 'Mixins are functions that take a class and return a new class with extra functionality. ' + - 'Useful for composition when single inheritance is not enough.', - task: 'Create a `Serializable` mixin that adds a toJSON method.', - hint: 'function Serializable>(Base: T)', + "Mixins are functions that take a class and return a new class with extra functionality. " + + "Useful for composition when single inheritance is not enough.", + task: "Create a `Serializable` mixin that adds a toJSON method.", + hint: "function Serializable>(Base: T)", starterCode: `type Constructor = new (...args: any[]) => T function Serializable>(Base: T) { @@ -1540,13 +1540,13 @@ console.log("User:", JSON.stringify(user, null, 2))`, }, { id: 50, - title: 'Declaration Merging', - level: 'advanced', + title: "Declaration Merging", + level: "advanced", content: 'TypeScript allows interfaces and namespaces with the same name to be "merged". ' + - 'Interfaces are merged automatically, namespaces require `export`.', - task: 'Create an interface that is merged with another.', - hint: 'interface Animal { name: string; } interface Animal { age: number; }', + "Interfaces are merged automatically, namespaces require `export`.", + task: "Create an interface that is merged with another.", + hint: "interface Animal { name: string; } interface Animal { age: number; }", starterCode: `interface User { name: string } @@ -1581,13 +1581,13 @@ console.log("Declaration merging works!")`, }, { id: 51, - title: 'Type-safe Event Emitter', - level: 'advanced', + title: "Type-safe Event Emitter", + level: "advanced", content: - 'Create a type-safe event emitter that guarantees listeners and events match. ' + - 'Use generics to map event names to their payloads.', - task: 'Create an EventMap type and implement an emitter.', - hint: 'type Events = { event: payload }', + "Create a type-safe event emitter that guarantees listeners and events match. " + + "Use generics to map event names to their payloads.", + task: "Create an EventMap type and implement an emitter.", + hint: "type Events = { event: payload }", starterCode: `type EventMap = { userJoined: { userId: number; name: string } userLeft: { userId: number } @@ -1629,13 +1629,13 @@ emitter.emit("message", { from: "Bob", text: "Hello!" })`, }, { id: 52, - title: 'Builder Pattern with Generics', - level: 'advanced', + title: "Builder Pattern with Generics", + level: "advanced", content: - 'The Builder pattern allows you to construct complex objects step by step. ' + - 'With generics, we can ensure methods return the correct builder.', - task: 'Implement a builder to create users with validation.', - hint: 'Use this return for method chaining.', + "The Builder pattern allows you to construct complex objects step by step. " + + "With generics, we can ensure methods return the correct builder.", + task: "Implement a builder to create users with validation.", + hint: "Use this return for method chaining.", starterCode: `class UserBuilder { private user: { name?: string; age?: number; email?: string } = {} @@ -1675,13 +1675,13 @@ console.log("Built user:", JSON.stringify(user))`, }, { id: 53, - title: 'Currying and Function Composition', - level: 'basic', + title: "Currying and Function Composition", + level: "basic", content: - 'Currying transforms multi-arg functions into sequences of single-arg functions. ' + - 'Composition combines functions to create data pipelines.', - task: 'Create curried functions and compose them.', - hint: 'const add = (a: number) => (b: number) => a + b', + "Currying transforms multi-arg functions into sequences of single-arg functions. " + + "Composition combines functions to create data pipelines.", + task: "Create curried functions and compose them.", + hint: "const add = (a: number) => (b: number) => a + b", starterCode: `const add = (a: number) => (b: number): number => a + b const multiply = (a: number) => (b: number): number => a * b const subtract = (a: number) => (b: number): number => a - b @@ -1707,13 +1707,13 @@ console.log("pipe(add10, double, subtract5)(5):", processNumber(5))`, }, { id: 54, - title: 'Type-safe API Client', - level: 'advanced', + title: "Type-safe API Client", + level: "advanced", content: - 'Create an HTTP client that automatically infers response types. ' + - 'Use generics to type endpoints and responses.', - task: 'Create a client with types for GET and POST.', - hint: 'class ApiClient { get(url): Promise }', + "Create an HTTP client that automatically infers response types. " + + "Use generics to type endpoints and responses.", + task: "Create a client with types for GET and POST.", + hint: "class ApiClient { get(url): Promise }", starterCode: `interface User { id: number name: string @@ -1760,13 +1760,13 @@ createUser({ name: "Alice", email: "alice@example.com" }) }, { id: 55, - title: 'Flattened Union Types', - level: 'advanced', + title: "Flattened Union Types", + level: "advanced", content: - 'Create complex union types and use distribution to transform them. ' + - 'Useful for automatically creating literal string unions.', - task: 'Create a union of HTTP methods from an array.', - hint: 'type Method = typeof methods[number]', + "Create complex union types and use distribution to transform them. " + + "Useful for automatically creating literal string unions.", + task: "Create a union of HTTP methods from an array.", + hint: "type Method = typeof methods[number]", starterCode: `const methods = ["get", "post", "put", "delete", "patch"] as const type HttpMethod = typeof methods[number] @@ -1807,13 +1807,13 @@ console.log("Variants:", variants)`, }, { id: 56, - title: 'Immutable Update Patterns', - level: 'basic', + title: "Immutable Update Patterns", + level: "basic", content: - 'Update objects and arrays immutably to avoid accidental mutations. ' + - 'Use spread operator and methods that return new arrays.', - task: 'Update a nested object immutably.', - hint: 'Use spread to create new references.', + "Update objects and arrays immutably to avoid accidental mutations. " + + "Use spread operator and methods that return new arrays.", + task: "Update a nested object immutably.", + hint: "Use spread to create new references.", starterCode: `interface State { user: { profile: { @@ -1863,13 +1863,13 @@ console.log("Same reference?", state === newState)`, }, { id: 57, - title: 'Recursive Types', - level: 'advanced', + title: "Recursive Types", + level: "advanced", content: - 'Recursive types allow you to represent hierarchical structures like trees and lists. ' + - 'Useful for JSON, ASTs, and nested data structures.', - task: 'Create a type for a directory tree.', - hint: 'interface TreeNode { name: string; children?: TreeNode[] }', + "Recursive types allow you to represent hierarchical structures like trees and lists. " + + "Useful for JSON, ASTs, and nested data structures.", + task: "Create a type for a directory tree.", + hint: "interface TreeNode { name: string; children?: TreeNode[] }", starterCode: `interface TreeNode { name: string type: "file" | "folder" @@ -1919,12 +1919,12 @@ console.log("JSON:", JSON.stringify(json, null, 2))`, }, { id: 58, - title: 'Branded Types', - level: 'advanced', + title: "Branded Types", + level: "advanced", content: 'Branded types add "tags" to existing types to distinguish primitive types. ' + - 'Useful for IDs, currencies, and values that need semantic validation.', - task: 'Create branded types for UserId and OrderId.', + "Useful for IDs, currencies, and values that need semantic validation.", + task: "Create branded types for UserId and OrderId.", hint: 'type UserId = string & { __brand: "UserId" }', starterCode: `type UserId = string & { readonly __brand: "UserId" } type OrderId = string & { readonly __brand: "OrderId" } @@ -1962,12 +1962,12 @@ console.log("Email:", email)`, }, { id: 59, - title: 'Finite State Machines', - level: 'advanced', + title: "Finite State Machines", + level: "advanced", content: - 'State machines define a finite number of states and transitions between them. ' + - 'TypeScript can ensure only valid transitions occur.', - task: 'Create a state machine for an order.', + "State machines define a finite number of states and transitions between them. " + + "TypeScript can ensure only valid transitions occur.", + task: "Create a state machine for an order.", hint: 'type State = "pending" | "shipped" | "delivered"', starterCode: `type OrderState = "pending" | "confirmed" | "shipped" | "delivered" | "cancelled" @@ -2022,12 +2022,12 @@ console.log("After deliver:", order.state)`, }, { id: 60, - title: 'Weak Types and Type Guards', - level: 'advanced', + title: "Weak Types and Type Guards", + level: "advanced", content: - 'Weak types are types with all properties optional. ' + - 'TypeScript has special checking to ensure at least one property is provided.', - task: 'Create a function that accepts only valid options.', + "Weak types are types with all properties optional. " + + "TypeScript has special checking to ensure at least one property is provided.", + task: "Create a function that accepts only valid options.", hint: 'Use "at least one" constraint with keyof', starterCode: `type Options = { timeout?: number @@ -2049,13 +2049,13 @@ configure({ timeout: 1000, retries: 5 })`, }, { id: 61, - title: 'Proxy and Interception', - level: 'advanced', + title: "Proxy and Interception", + level: "advanced", content: - 'Proxy allows you to intercept operations like reading, writing, and method invocation. ' + - 'Useful for logging, validation, and lazy loading.', - task: 'Create a proxy to validate properties.', - hint: 'new Proxy(target, { get, set })', + "Proxy allows you to intercept operations like reading, writing, and method invocation. " + + "Useful for logging, validation, and lazy loading.", + task: "Create a proxy to validate properties.", + hint: "new Proxy(target, { get, set })", starterCode: `interface User { name: string age: number @@ -2095,12 +2095,12 @@ try { }, { id: 62, - title: 'Symbol and Metadata', - level: 'basic', + title: "Symbol and Metadata", + level: "basic", content: - 'Symbols are unique values that can serve as property keys. ' + + "Symbols are unique values that can serve as property keys. " + 'Useful for creating "hidden" properties and for reflection.', - task: 'Use Symbol to create a private property.', + task: "Use Symbol to create a private property.", hint: 'const privateKey = Symbol("private")', starterCode: `const nameKey = Symbol("name") const ageKey = Symbol("age") @@ -2137,13 +2137,13 @@ console.log("Cached:", cache.get(key1))`, }, { id: 63, - title: 'Asserts Type Guards', - level: 'advanced', + title: "Asserts Type Guards", + level: "advanced", content: - 'Asserts type guards are functions that verify and refine types, ' + - 'throwing an error if the condition is not met.', - task: 'Create an assert that checks if a value is a positive number.', - hint: 'function assert(condition, message)', + "Asserts type guards are functions that verify and refine types, " + + "throwing an error if the condition is not met.", + task: "Create an assert that checks if a value is a positive number.", + hint: "function assert(condition, message)", starterCode: `function assert(condition: boolean, message: string): asserts condition { if (!condition) { throw new Error(message) @@ -2177,13 +2177,13 @@ console.log("Data length:", data.length)`, }, { id: 64, - title: 'Infer with Conditional Types', - level: 'advanced', + title: "Infer with Conditional Types", + level: "advanced", content: - '`infer` extracts types from inside other types. ' + - 'It can extract types from functions, arrays, promises, and objects.', - task: 'Extract the element type from an array.', - hint: 'type ArrayElement = T extends (infer U)[] ? U : never', + "`infer` extracts types from inside other types. " + + "It can extract types from functions, arrays, promises, and objects.", + task: "Extract the element type from an array.", + hint: "type ArrayElement = T extends (infer U)[] ? U : never", starterCode: `type ReturnTypeOf = T extends (...args: any[]) => infer R ? R : never type ParametersOf = T extends (...args: infer P) => any ? P : never type ArrayElement = T extends (infer U)[] ? U : never @@ -2216,13 +2216,13 @@ console.log("Promise:", pv)`, }, { id: 65, - title: 'Type-safe Event Bus', - level: 'advanced', + title: "Type-safe Event Bus", + level: "advanced", content: - 'Create an event bus that guarantees type safety for events and handlers. ' + - 'Use mapped types to derive event types.', - task: 'Implement an event bus with type-safe subscribe and emit.', - hint: 'Use keyof and generics for inference.', + "Create an event bus that guarantees type safety for events and handlers. " + + "Use mapped types to derive event types.", + task: "Implement an event bus with type-safe subscribe and emit.", + hint: "Use keyof and generics for inference.", starterCode: `type Events = { login: { userId: number; timestamp: Date } logout: { userId: number } @@ -2277,13 +2277,13 @@ bus.emit("purchase", { userId: 1, amount: 99.99 })`, }, { id: 66, - title: 'Deep Readonly', - level: 'advanced', + title: "Deep Readonly", + level: "advanced", content: - 'Create a type that makes all nested properties readonly recursively. ' + - 'Useful for ensuring immutability in complex objects.', - task: 'Create a DeepReadonly type.', - hint: 'type DeepReadonly = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K] }', + "Create a type that makes all nested properties readonly recursively. " + + "Useful for ensuring immutability in complex objects.", + task: "Create a DeepReadonly type.", + hint: "type DeepReadonly = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K] }", starterCode: `type DeepReadonly = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K] } @@ -2315,13 +2315,13 @@ console.log("Company:", JSON.stringify(company, null, 2))`, }, { id: 67, - title: 'Strict Null Checks in Filters', - level: 'basic', + title: "Strict Null Checks in Filters", + level: "basic", content: - 'Filtering arrays can create union types with undefined. ' + - 'Learn to use type guards to properly refine them.', - task: 'Filter null values and refine the type.', - hint: 'arr.filter((x): x is Type => x !== null)', + "Filtering arrays can create union types with undefined. " + + "Learn to use type guards to properly refine them.", + task: "Filter null values and refine the type.", + hint: "arr.filter((x): x is Type => x !== null)", starterCode: `interface User { id: number name: string @@ -2357,12 +2357,12 @@ if (result) { }, { id: 68, - title: 'Enum vs Union vs Const Object', - level: 'basic', + title: "Enum vs Union vs Const Object", + level: "basic", content: - 'Compare enums, union types, and const objects to understand when to use each. ' + - 'Each approach has pros and cons in terms of runtime and type safety.', - task: 'Convert an enum to a union type and compare.', + "Compare enums, union types, and const objects to understand when to use each. " + + "Each approach has pros and cons in terms of runtime and type safety.", + task: "Convert an enum to a union type and compare.", hint: 'type Direction = "N" | "S" | "E" | "W"', starterCode: `enum DirectionEnum { North = "N", @@ -2397,13 +2397,12 @@ console.log("All approaches work!")`, }, { id: 69, - title: 'Type-safe CSV Parser', - level: 'advanced', + title: "Type-safe CSV Parser", + level: "advanced", content: - 'Create a CSV parser that infers column types. ' + - 'Use generics to map headers to types.', - task: 'Parse CSV and infer column types.', - hint: 'function parseCSV(csv: string): T[]', + "Create a CSV parser that infers column types. " + "Use generics to map headers to types.", + task: "Parse CSV and infer column types.", + hint: "function parseCSV(csv: string): T[]", starterCode: `interface User { id: number name: string @@ -2447,13 +2446,13 @@ console.log("First user:", first)`, }, { id: 70, - title: 'Schema Validation with Mapped Types', - level: 'advanced', + title: "Schema Validation with Mapped Types", + level: "advanced", content: - 'Create a schema validator that checks objects against type definitions. ' + - 'Use mapped types to transform the schema into validators.', - task: 'Validate an object against a schema.', - hint: 'Use Record to map fields to validators.', + "Create a schema validator that checks objects against type definitions. " + + "Use mapped types to transform the schema into validators.", + task: "Validate an object against a schema.", + hint: "Use Record to map fields to validators.", starterCode: `type Validator = (value: unknown) => T type Schema = { @@ -2507,13 +2506,13 @@ console.log("Validated:", validated)`, }, { id: 71, - title: 'Polymorphic this Types', - level: 'advanced', + title: "Polymorphic this Types", + level: "advanced", content: - 'Use `this` as return type to create fluent APIs where methods return ' + - 'the concrete class, not the base class. Useful for inheritance.', - task: 'Create a fluent API with polymorphic this.', - hint: 'class Builder { add(): this { } }', + "Use `this` as return type to create fluent APIs where methods return " + + "the concrete class, not the base class. Useful for inheritance.", + task: "Create a fluent API with polymorphic this.", + hint: "class Builder { add(): this { } }", starterCode: `class Builder { protected parts: string[] = [] @@ -2576,13 +2575,13 @@ console.log("Result:", calc.result())`, }, { id: 72, - title: 'Tuple Types in Functions', - level: 'basic', + title: "Tuple Types in Functions", + level: "basic", content: - 'Tuples can be used to type function parameters with multiple values. ' + - 'Useful for functions that return multiple values.', - task: 'Create a function that returns name and age as a tuple.', - hint: 'function getPerson(): [string, number] { }', + "Tuples can be used to type function parameters with multiple values. " + + "Useful for functions that return multiple values.", + task: "Create a function that returns name and age as a tuple.", + hint: "function getPerson(): [string, number] { }", starterCode: `function getUser(): [string, number, boolean] { return ["Alice", 25, true] } @@ -2619,13 +2618,13 @@ console.log("Parsed:", date)`, }, { id: 73, - title: 'Interface vs Type Alias', - level: 'basic', + title: "Interface vs Type Alias", + level: "basic", content: - 'Interfaces are better for objects and classes, allowing extends and merge. ' + - 'Type aliases are better for unions, intersections, and primitive types.', - task: 'Compare interface and type for the same object.', - hint: 'interface for objects, type for unions', + "Interfaces are better for objects and classes, allowing extends and merge. " + + "Type aliases are better for unions, intersections, and primitive types.", + task: "Compare interface and type for the same object.", + hint: "interface for objects, type for unions", starterCode: `interface UserI { name: string age: number @@ -2662,12 +2661,12 @@ console.log("Pair:", pair)`, }, { id: 74, - title: 'Module Resolution', - level: 'advanced', + title: "Module Resolution", + level: "advanced", content: - 'TypeScript resolves modules in different ways: classic, node, node16, nodenext. ' + - 'Understand the differences to configure projects correctly.', - task: 'Configure paths and baseUrl for imports.', + "TypeScript resolves modules in different ways: classic, node, node16, nodenext. " + + "Understand the differences to configure projects correctly.", + task: "Configure paths and baseUrl for imports.", hint: 'Configure "baseUrl" and "paths" in tsconfig.json', starterCode: `// Simulating tsconfig paths // { @@ -2703,12 +2702,12 @@ console.log("Resolved @/components:", resolvePath("@/components"))`, }, { id: 75, - title: 'Ambient Modules and Triple-Slash', - level: 'advanced', + title: "Ambient Modules and Triple-Slash", + level: "advanced", content: - 'Use triple-slash directives to declare module dependencies. ' + - 'Useful for including types and modules in compiled files.', - task: 'Use triple-slash to declare a module.', + "Use triple-slash directives to declare module dependencies. " + + "Useful for including types and modules in compiled files.", + task: "Use triple-slash to declare a module.", hint: '/// ', starterCode: `/// @@ -2731,13 +2730,13 @@ console.log("Ambient declarations loaded!")`, }, { id: 76, - title: 'Union Narrowing with never', - level: 'advanced', + title: "Union Narrowing with never", + level: "advanced", content: - 'Use `never` in unions to force TypeScript to check all cases. ' + - 'Useful in exhaustive switch statements.', - task: 'Create an exhaustive switch.', - hint: 'default: const _: never = value', + "Use `never` in unions to force TypeScript to check all cases. " + + "Useful in exhaustive switch statements.", + task: "Create an exhaustive switch.", + hint: "default: const _: never = value", starterCode: `type Shape = | { kind: "circle"; radius: number } | { kind: "square"; side: number } @@ -2767,13 +2766,13 @@ shapes.forEach(s => console.log(\`Area: \${area(s).toFixed(2)}\`))`, }, { id: 77, - title: 'Type-safe Event Listeners', - level: 'advanced', + title: "Type-safe Event Listeners", + level: "advanced", content: - 'Create functions that add event listeners with full type safety. ' + - 'The handler should have the correct type based on the event.', - task: 'Create a type-safe addEventListener function.', - hint: 'Use generics to infer the handler type.', + "Create functions that add event listeners with full type safety. " + + "The handler should have the correct type based on the event.", + task: "Create a type-safe addEventListener function.", + hint: "Use generics to infer the handler type.", starterCode: `type EventMap = { click: { x: number; y: number } keydown: { key: string } @@ -2810,13 +2809,13 @@ on("focus", () => console.log("focused"))`, }, { id: 78, - title: 'Intersection Types with Mixins', - level: 'advanced', + title: "Intersection Types with Mixins", + level: "advanced", content: - 'Intersection types combine multiple types into one. ' + - 'Useful for adding functionality via mixins or creating complex types.', - task: 'Create a type that is both Serializable and Validatable.', - hint: 'type T = Serializable & Validatable', + "Intersection types combine multiple types into one. " + + "Useful for adding functionality via mixins or creating complex types.", + task: "Create a type that is both Serializable and Validatable.", + hint: "type T = Serializable & Validatable", starterCode: `interface Serializable { toJSON(): Record } @@ -2871,13 +2870,13 @@ io.write("hello")`, }, { id: 79, - title: 'Type-safe Console Methods', - level: 'basic', + title: "Type-safe Console Methods", + level: "basic", content: "TypeScript doesn't check console by default. " + - 'Create type-safe wrappers for consistent logging.', - task: 'Create type-safe logging functions.', - hint: 'function log(message: T): void', + "Create type-safe wrappers for consistent logging.", + task: "Create type-safe logging functions.", + hint: "function log(message: T): void", starterCode: `function log(message: T): void { console.log(\`[LOG] \${message}\`) } @@ -2907,13 +2906,13 @@ console.log("Result:", result)`, }, { id: 80, - title: 'Simple Pattern Matching', - level: 'basic', + title: "Simple Pattern Matching", + level: "basic", content: - 'Implement simple pattern matching with generics. ' + - 'Similar to match in functional languages.', - task: 'Create a match function that executes patterns.', - hint: 'function match(value: T, patterns: Record): R', + "Implement simple pattern matching with generics. " + + "Similar to match in functional languages.", + task: "Create a match function that executes patterns.", + hint: "function match(value: T, patterns: Record): R", starterCode: `function match(value: T, patterns: Record): R { if (value in patterns) { return patterns[value] @@ -2958,13 +2957,13 @@ console.log(reduce({ type: "reset" }))`, }, { id: 81, - title: 'Variadic Tuple Types', - level: 'advanced', + title: "Variadic Tuple Types", + level: "advanced", content: - 'Variadic tuples allow creating types that accept a variable number of elements. ' + - 'Useful for type concatenation and tail recursion.', - task: 'Create a type that concatenates tuples.', - hint: 'type Concat = [...T, ...U]', + "Variadic tuples allow creating types that accept a variable number of elements. " + + "Useful for type concatenation and tail recursion.", + task: "Create a type that concatenates tuples.", + hint: "type Concat = [...T, ...U]", starterCode: `type Concat = [...T, ...U] type A = Concat<[1, 2], [3, 4]> @@ -2990,13 +2989,13 @@ const d: D = [2, 3]`, }, { id: 82, - title: 'Awaited Type for Promises', - level: 'advanced', + title: "Awaited Type for Promises", + level: "advanced", content: - 'The utility type `Awaited` extracts the resolved type of a Promise. ' + - 'It works recursively for nested Promises.', - task: 'Use Awaited to type the result of async functions.', - hint: 'type Result = Awaited>', + "The utility type `Awaited` extracts the resolved type of a Promise. " + + "It works recursively for nested Promises.", + task: "Use Awaited to type the result of async functions.", + hint: "type Result = Awaited>", starterCode: `type Awaited = T extends Promise ? Awaited : T async function fetchUser(): Promise<{ id: number; name: string }> { @@ -3025,11 +3024,11 @@ getData()`, }, { id: 83, - title: 'Brand Keys in Mapped Types', - level: 'advanced', + title: "Brand Keys in Mapped Types", + level: "advanced", content: - 'Use template literal types in mapped types to create key transformations. ' + - 'Useful for adding prefixes/suffixes or converting conventions.', + "Use template literal types in mapped types to create key transformations. " + + "Useful for adding prefixes/suffixes or converting conventions.", task: "Create a mapped type that adds 'get' prefix to methods.", hint: "type WithGetters = { [K in keyof T as 'get' + K]: () => T[K] }", starterCode: `type WithGetters = { @@ -3069,13 +3068,13 @@ setters.setName("Bob")`, }, { id: 84, - title: 'Type-safe React-like setState', - level: 'advanced', + title: "Type-safe React-like setState", + level: "advanced", content: "Implement a state hook similar to React's useState. " + - 'The setter should allow partial updates and infer types correctly.', - task: 'Create a simplified useState with inferred types.', - hint: 'function useState(initial: T): [() => T, (value: T | ((prev: T) => T)) => void]', + "The setter should allow partial updates and infer types correctly.", + task: "Create a simplified useState with inferred types.", + hint: "function useState(initial: T): [() => T, (value: T | ((prev: T) => T)) => void]", starterCode: `function useState(initial: T) { let state = initial @@ -3108,13 +3107,13 @@ console.log("Final count:", count())`, }, { id: 85, - title: 'Deep Partial Type', - level: 'advanced', + title: "Deep Partial Type", + level: "advanced", content: - 'Partial makes first-level properties optional. ' + - 'DeepPartial makes ALL nested properties optional recursively.', - task: 'Create a DeepPartial type.', - hint: 'type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] }', + "Partial makes first-level properties optional. " + + "DeepPartial makes ALL nested properties optional recursively.", + task: "Create a DeepPartial type.", + hint: "type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] }", starterCode: `type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] } @@ -3168,13 +3167,13 @@ function updateCompany(current: Company, updates: PartialCompany): Company { }, { id: 86, - title: 'Extract Keys by Value Type', - level: 'advanced', + title: "Extract Keys by Value Type", + level: "advanced", content: - 'Create a type that extracts keys from an object based on the type of its values. ' + - 'Useful for finding fields of a certain type.', - task: 'Extract keys whose values are of type string.', - hint: 'type KeysOfType = { [K in keyof T]: T[K] extends U ? K : never }[keyof T]', + "Create a type that extracts keys from an object based on the type of its values. " + + "Useful for finding fields of a certain type.", + task: "Extract keys whose values are of type string.", + hint: "type KeysOfType = { [K in keyof T]: T[K] extends U ? K : never }[keyof T]", starterCode: `type KeysOfType = { [K in keyof T]: T[K] extends U ? K : never }[keyof T] @@ -3217,12 +3216,12 @@ console.log("Numbers:", numbers)`, }, { id: 87, - title: 'Type-safe Redux-like Reducer', - level: 'advanced', + title: "Type-safe Redux-like Reducer", + level: "advanced", content: - 'Implement a type-safe reducer similar to Redux. ' + - 'The action type determines which payloads are valid.', - task: 'Create a reducer with type-safe actions.', + "Implement a type-safe reducer similar to Redux. " + + "The action type determines which payloads are valid.", + task: "Create a reducer with type-safe actions.", hint: 'type Action = { type: "TYPE"; payload: T }', starterCode: `type Action = | { type: "increment"; payload: number } @@ -3273,13 +3272,13 @@ console.log("After reset:", state.count)`, }, { id: 88, - title: 'Constructor Parameters Type', - level: 'advanced', + title: "Constructor Parameters Type", + level: "advanced", content: "`ConstructorParameters` extracts the parameter types of T's constructor. " + - 'Useful for creating factories and dependency injection.', - task: 'Use ConstructorParameters to create a factory.', - hint: 'type CtorParams = ConstructorParameters', + "Useful for creating factories and dependency injection.", + task: "Use ConstructorParameters to create a factory.", + hint: "type CtorParams = ConstructorParameters", starterCode: `type ConstructorParameters any> = T extends new (...args: infer P) => any ? P : never @@ -3320,13 +3319,13 @@ console.log("Product:", product.name, product.price)`, }, { id: 89, - title: 'Optional Keys and Required Keys', - level: 'advanced', + title: "Optional Keys and Required Keys", + level: "advanced", content: - '`Required` makes all properties required. ' + - '`Optional` (custom) can do the opposite, or create types that have only optionals.', - task: 'Extract optional and required keys separately.', - hint: 'type OptionalKeys = { [K in keyof T]: T extends { [K]: T[K] } ? never : K }[keyof T]', + "`Required` makes all properties required. " + + "`Optional` (custom) can do the opposite, or create types that have only optionals.", + task: "Extract optional and required keys separately.", + hint: "type OptionalKeys = { [K in keyof T]: T extends { [K]: T[K] } ? never : K }[keyof T]", starterCode: `type OptionalKeys = { [K in keyof T]: {} extends Pick ? K : never }[keyof T] @@ -3364,13 +3363,13 @@ console.log("Validation:", result)`, }, { id: 90, - title: 'Type-safe Event Bus Final', - level: 'advanced', + title: "Type-safe Event Bus Final", + level: "advanced", content: - 'Combine everything: generics, conditional types, and mapped types ' + - 'to create a completely type-safe event bus.', - task: 'Create an event bus with inferred handlers.', - hint: 'Use infer to extract event types.', + "Combine everything: generics, conditional types, and mapped types " + + "to create a completely type-safe event bus.", + task: "Create an event bus with inferred handlers.", + hint: "Use infer to extract event types.", starterCode: `type EventMap = Record type EventReceiver = (params: T) => void @@ -3422,13 +3421,13 @@ bus.emit("purchase", { amount: 99.99, item: "E-book" })`, }, { id: 91, - title: 'Omit vs Exclude', - level: 'basic', + title: "Omit vs Exclude", + level: "basic", content: - '`Omit` removes properties from an object type. ' + - '`Exclude` removes types from a union. Understand the difference.', - task: 'Use Omit for objects and Exclude for unions.', - hint: 'Omit for objects, Exclude for unions', + "`Omit` removes properties from an object type. " + + "`Exclude` removes types from a union. Understand the difference.", + task: "Use Omit for objects and Exclude for unions.", + hint: "Omit for objects, Exclude for unions", starterCode: `interface User { id: number name: string @@ -3462,13 +3461,13 @@ console.log("Primary colors:", primaries)`, }, { id: 92, - title: 'Typed Object.entries and Object.keys', - level: 'basic', + title: "Typed Object.entries and Object.keys", + level: "basic", content: - 'Object.entries and Object.keys return `string[]` by default. ' + - 'Use assertion or generics to type them correctly.', - task: 'Iterate over an object with correct types.', - hint: 'Use as Array<[keyof T, T[keyof T]]>', + "Object.entries and Object.keys return `string[]` by default. " + + "Use assertion or generics to type them correctly.", + task: "Iterate over an object with correct types.", + hint: "Use as Array<[keyof T, T[keyof T]]>", starterCode: `interface User { id: number name: string @@ -3503,13 +3502,13 @@ typedEntries({ a: 1, b: 2, c: 3 }).forEach(([k, v]) => { }, { id: 93, - title: 'Strict Property Initialization', - level: 'basic', + title: "Strict Property Initialization", + level: "basic", content: - 'With strictPropertyInitialization, class properties must be initialized ' + - 'in the constructor or with initialization shorthand.', - task: 'Initialize properties correctly.', - hint: 'Use constructor or initialization shorthand.', + "With strictPropertyInitialization, class properties must be initialized " + + "in the constructor or with initialization shorthand.", + task: "Initialize properties correctly.", + hint: "Use constructor or initialization shorthand.", starterCode: `class User { name: string age: number @@ -3554,13 +3553,13 @@ console.log("Name:", opt.name)`, }, { id: 94, - title: 'Type-safe Fetch Wrapper', - level: 'advanced', + title: "Type-safe Fetch Wrapper", + level: "advanced", content: - 'Create a type-safe wrapper for fetch that infers the response type. ' + - 'Supports JSON, text, and status checking.', - task: 'Create a type-safe fetchJson function.', - hint: 'async function fetchJson(url: string): Promise', + "Create a type-safe wrapper for fetch that infers the response type. " + + "Supports JSON, text, and status checking.", + task: "Create a type-safe fetchJson function.", + hint: "async function fetchJson(url: string): Promise", starterCode: `async function fetchJson( url: string, options?: RequestInit @@ -3611,13 +3610,13 @@ main()`, }, { id: 95, - title: 'Type-safe Route Handler', - level: 'advanced', + title: "Type-safe Route Handler", + level: "advanced", content: - 'Create a type-safe router where each route has its handler with specific types. ' + - 'The handler receives only the parameters defined for that route.', - task: 'Create type-safe route handlers.', - hint: 'Use Record to map routes to handlers.', + "Create a type-safe router where each route has its handler with specific types. " + + "The handler receives only the parameters defined for that route.", + task: "Create type-safe route handlers.", + hint: "Use Record to map routes to handlers.", starterCode: `type RouteHandler = (params: T) => string | Promise interface Route { @@ -3672,12 +3671,12 @@ console.log(matchRoute("/posts/456?draft=true", routes))`, }, { id: 96, - title: 'Generic Record Factory', - level: 'advanced', + title: "Generic Record Factory", + level: "advanced", content: - 'Create a factory that generates typed objects with useful methods. ' + - 'The return type should be completely inferred.', - task: 'Create a factory to generate objects with IDs.', + "Create a factory that generates typed objects with useful methods. " + + "The return type should be completely inferred.", + task: "Create a factory to generate objects with IDs.", hint: 'function create(data: Omit): T & { id: string }', starterCode: `function createEntity( data: T @@ -3733,13 +3732,13 @@ console.log("Numbers:", [...numbers])`, }, { id: 97, - title: 'Reverse Engineering Types', - level: 'advanced', + title: "Reverse Engineering Types", + level: "advanced", content: - 'Given an object, derive its type automatically. ' + - 'Use `typeof` to create types from values.', - task: 'Use typeof to create types from objects.', - hint: 'type T = typeof myObject', + "Given an object, derive its type automatically. " + + "Use `typeof` to create types from values.", + task: "Use typeof to create types from objects.", + hint: "type T = typeof myObject", starterCode: `const user = { id: 1, name: "Alice", @@ -3789,12 +3788,12 @@ type Method = typeof constObj.GET | typeof constObj.POST`, }, { id: 98, - title: 'Chaining Optionals', - level: 'basic', + title: "Chaining Optionals", + level: "basic", content: - 'When accessing nested optional properties, you can use optional chaining ' + - 'to avoid errors. Learn to handle undefined at depth.', - task: 'Access deep properties with safety.', + "When accessing nested optional properties, you can use optional chaining " + + "to avoid errors. Learn to handle undefined at depth.", + task: "Access deep properties with safety.", hint: 'user?.address?.city ?? "unknown"', starterCode: `interface User { name: string @@ -3838,13 +3837,13 @@ console.log("getCity:", getCity(user1), getCity(user2))`, }, { id: 99, - title: 'Type-safe Event-Driven Architecture', - level: 'advanced', + title: "Type-safe Event-Driven Architecture", + level: "advanced", content: - 'Create an event system where emitters and listeners are type-safe. ' + - 'The event type determines the available data.', - task: 'Implement subscribe/publish with derived types.', - hint: 'Use generic to relate event and data.', + "Create an event system where emitters and listeners are type-safe. " + + "The event type determines the available data.", + task: "Implement subscribe/publish with derived types.", + hint: "Use generic to relate event and data.", starterCode: `type EventMap = { userCreated: { id: number; email: string } userUpdated: { id: number; changes: Record } @@ -3892,14 +3891,14 @@ emitter.emit("userUpdated", { id: 1, changes: { name: "Alice", age: 26 } })`, }, { id: 100, - title: 'Conclusion: Next Steps', - level: 'basic', + title: "Conclusion: Next Steps", + level: "basic", content: - 'Congratulations on completing 100 TypeScript lessons! You now have a solid foundation. ' + - 'Next steps: contribute to open source projects, explore libraries like React/Next.js, ' + - 'and practice with coding challenges.', + "Congratulations on completing 100 TypeScript lessons! You now have a solid foundation. " + + "Next steps: contribute to open source projects, explore libraries like React/Next.js, " + + "and practice with coding challenges.", task: "Review what you've learned and keep practicing!", - hint: 'Practice leads to mastery!', + hint: "Practice leads to mastery!", starterCode: `console.log("🎉 Congratulations!") console.log("") console.log("You completed 100 TypeScript lessons!") @@ -3927,13 +3926,13 @@ console.log("Good journey! 🚀")`, }, { id: 101, - title: 'typeof with Objects', - level: 'medium', + title: "typeof with Objects", + level: "medium", content: - 'Use `typeof` to get the type of a variable or object. ' + - 'This automatically creates a type based on the value.', - task: 'Get the type of an object using typeof.', - hint: 'type T = typeof myObject', + "Use `typeof` to get the type of a variable or object. " + + "This automatically creates a type based on the value.", + task: "Get the type of an object using typeof.", + hint: "type T = typeof myObject", starterCode: `const user = { name: "Alice", age: 25, @@ -3952,13 +3951,12 @@ console.log("New user:", newUser)`, }, { id: 102, - title: '&& and || Operators', - level: 'medium', + title: "&& and || Operators", + level: "medium", content: - 'Logical operators work like in JavaScript. ' + - 'Learn to use them with conditional types.', - task: 'Use logical operators in expressions.', - hint: 'const result = a && b || c', + "Logical operators work like in JavaScript. " + "Learn to use them with conditional types.", + task: "Use logical operators in expressions.", + hint: "const result = a && b || c", starterCode: `const a = true const b = false const c = true @@ -3977,13 +3975,13 @@ console.log("OR result:", orResult)`, }, { id: 103, - title: 'Ternary Operator', - level: 'medium', + title: "Ternary Operator", + level: "medium", content: - 'The ternary operator `condition ? value1 : value2` is useful for simple conditions. ' + - 'It can also be used in types with conditional types.', - task: 'Use the ternary operator to choose values.', - hint: 'const result = condition ? value1 : value2', + "The ternary operator `condition ? value1 : value2` is useful for simple conditions. " + + "It can also be used in types with conditional types.", + task: "Use the ternary operator to choose values.", + hint: "const result = condition ? value1 : value2", starterCode: `const age = 18 const status = age >= 18 ? "adult" : "minor" console.log("Status:", status) @@ -4001,13 +3999,13 @@ console.log(hasItems)`, }, { id: 104, - title: 'Arrow Functions', - level: 'medium', + title: "Arrow Functions", + level: "medium", content: - 'Arrow functions are more concise anonymous functions. ' + - 'TypeScript infers parameter and return types.', - task: 'Create typed arrow functions.', - hint: 'const fn = (x: number): number => x * 2', + "Arrow functions are more concise anonymous functions. " + + "TypeScript infers parameter and return types.", + task: "Create typed arrow functions.", + hint: "const fn = (x: number): number => x * 2", starterCode: `const add = (a: number, b: number): number => a + b const greet = (name: string): string => \`Hello, \${name}!\` const double = (x: number) => x * 2 @@ -4025,13 +4023,13 @@ console.log(process(numbers, double))`, }, { id: 105, - title: 'Spread in Objects', - level: 'medium', + title: "Spread in Objects", + level: "medium", content: - 'The spread operator `...` copies properties from objects. ' + - 'Useful for creating copies and merging objects.', - task: 'Use spread to merge objects.', - hint: 'const merged = { ...obj1, ...obj2 }', + "The spread operator `...` copies properties from objects. " + + "Useful for creating copies and merging objects.", + task: "Use spread to merge objects.", + hint: "const merged = { ...obj1, ...obj2 }", starterCode: `const defaults = { theme: "dark", language: "pt-BR" } const userPrefs = { theme: "light" } @@ -4049,13 +4047,13 @@ console.log("Full:", full)`, }, { id: 106, - title: 'Spread in Arrays', - level: 'medium', + title: "Spread in Arrays", + level: "medium", content: - 'Spread in arrays creates new copies or concatenates arrays. ' + - 'Does not modify the original array (immutability).', - task: 'Use spread to manipulate arrays.', - hint: 'const combined = [...arr1, ...arr2]', + "Spread in arrays creates new copies or concatenates arrays. " + + "Does not modify the original array (immutability).", + task: "Use spread to manipulate arrays.", + hint: "const combined = [...arr1, ...arr2]", starterCode: `const arr1 = [1, 2, 3] const arr2 = [4, 5, 6] @@ -4074,13 +4072,13 @@ console.log("Doubled:", updated)`, }, { id: 107, - title: 'Object Destructuring', - level: 'medium', + title: "Object Destructuring", + level: "medium", content: - 'Destructuring extracts properties from objects into variables. ' + - 'Can use default values for optional properties.', - task: 'Extract properties from an object.', - hint: 'const { name, age } = user', + "Destructuring extracts properties from objects into variables. " + + "Can use default values for optional properties.", + task: "Extract properties from an object.", + hint: "const { name, age } = user", starterCode: `const user = { name: "Alice", age: 25, @@ -4101,13 +4099,13 @@ console.log(greet(user))`, }, { id: 108, - title: 'Array Destructuring', - level: 'medium', + title: "Array Destructuring", + level: "medium", content: - 'Array destructuring uses position, not names. ' + - 'Can ignore elements or use rest parameters.', - task: 'Extract elements from an array by position.', - hint: 'const [first, second] = arr', + "Array destructuring uses position, not names. " + + "Can ignore elements or use rest parameters.", + task: "Extract elements from an array by position.", + hint: "const [first, second] = arr", starterCode: `const coords = [10, 20, 30] const [x, y, z] = coords console.log("Coords:", x, y, z) @@ -4127,13 +4125,13 @@ console.log("Sum:", sum([5, 3]))`, }, { id: 109, - title: 'Array Methods - map', - level: 'medium', + title: "Array Methods - map", + level: "medium", content: - 'map creates a new array transforming each element. ' + - 'TypeScript infers the type of the resulting array.', - task: 'Use map to transform an array.', - hint: 'const doubled = nums.map(n => n * 2)', + "map creates a new array transforming each element. " + + "TypeScript infers the type of the resulting array.", + task: "Use map to transform an array.", + hint: "const doubled = nums.map(n => n * 2)", starterCode: `const numbers = [1, 2, 3, 4, 5] const doubled = numbers.map(n => n * 2) @@ -4164,13 +4162,13 @@ console.log("Birthdays:", birthdays)`, }, { id: 110, - title: 'Array Methods - filter', - level: 'medium', + title: "Array Methods - filter", + level: "medium", content: - 'filter creates a new array with elements that pass the test. ' + - 'TypeScript automatically refines the type.', - task: 'Filter an array using filter.', - hint: 'const evens = nums.filter(n => n % 2 === 0)', + "filter creates a new array with elements that pass the test. " + + "TypeScript automatically refines the type.", + task: "Filter an array using filter.", + hint: "const evens = nums.filter(n => n % 2 === 0)", starterCode: `const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] const evens = numbers.filter(n => n % 2 === 0) @@ -4202,13 +4200,11 @@ console.log("Under 1000:", affordable)`, }, { id: 111, - title: 'Array Methods - reduce', - level: 'medium', - content: - 'reduce reduces an array to a single value. ' + - 'The accumulator can be any type.', - task: 'Sum all numbers in an array.', - hint: 'const sum = arr.reduce((acc, n) => acc + n, 0)', + title: "Array Methods - reduce", + level: "medium", + content: "reduce reduces an array to a single value. " + "The accumulator can be any type.", + task: "Sum all numbers in an array.", + hint: "const sum = arr.reduce((acc, n) => acc + n, 0)", starterCode: `const numbers = [1, 2, 3, 4, 5] const sum = numbers.reduce((acc, n) => acc + n, 0) @@ -4242,13 +4238,13 @@ console.log("By age:", byAge)`, }, { id: 112, - title: 'Array Methods - find and findIndex', - level: 'medium', + title: "Array Methods - find and findIndex", + level: "medium", content: - 'find returns the first element that satisfies the condition. ' + - 'findIndex returns its position.', - task: 'Find an element in the array.', - hint: 'const found = arr.find(x => x.id === 1)', + "find returns the first element that satisfies the condition. " + + "findIndex returns its position.", + task: "Find an element in the array.", + hint: "const found = arr.find(x => x.id === 1)", starterCode: `const numbers = [10, 20, 30, 40, 50] const found = numbers.find(n => n > 25) @@ -4276,13 +4272,12 @@ console.log("Index:", userIndex)`, }, { id: 113, - title: 'Array Methods - some and every', - level: 'medium', + title: "Array Methods - some and every", + level: "medium", content: - 'some returns true if any element passes the test. ' + - 'every returns true if all pass.', - task: 'Check conditions in arrays.', - hint: 'const hasEvens = arr.some(n => n % 2 === 0)', + "some returns true if any element passes the test. " + "every returns true if all pass.", + task: "Check conditions in arrays.", + hint: "const hasEvens = arr.some(n => n % 2 === 0)", starterCode: `const numbers = [1, 3, 5, 7, 9] const hasEvens = numbers.some(n => n % 2 === 0) @@ -4313,13 +4308,13 @@ console.log("All available:", allAvailable)`, }, { id: 114, - title: 'Array Methods - includes and indexOf', - level: 'medium', + title: "Array Methods - includes and indexOf", + level: "medium", content: - 'includes checks if a value exists in the array. ' + - 'indexOf returns the position or -1 if not found.', - task: 'Check if a value exists in the array.', - hint: 'const exists = arr.includes(value)', + "includes checks if a value exists in the array. " + + "indexOf returns the position or -1 if not found.", + task: "Check if a value exists in the array.", + hint: "const exists = arr.includes(value)", starterCode: `const fruits = ["apple", "banana", "orange"] console.log("Has banana:", fruits.includes("banana")) @@ -4344,13 +4339,12 @@ console.log("Unique:", unique([1, 2, 2, 3, 3, 3]))`, }, { id: 115, - title: 'Array Methods - sort', - level: 'medium', + title: "Array Methods - sort", + level: "medium", content: - 'sort sorts elements in place. ' + - 'For correct sorting, provide a comparator function.', - task: 'Sort an array of numbers.', - hint: 'const sorted = arr.sort((a, b) => a - b)', + "sort sorts elements in place. " + "For correct sorting, provide a comparator function.", + task: "Sort an array of numbers.", + hint: "const sorted = arr.sort((a, b) => a - b)", starterCode: `const numbers = [5, 2, 8, 1, 9] const ascending = [...numbers].sort((a, b) => a - b) @@ -4378,13 +4372,13 @@ console.log("By age:", byAge.map(u => u.name))`, }, { id: 116, - title: 'Array Methods - slice and splice', - level: 'medium', + title: "Array Methods - slice and splice", + level: "medium", content: - 'slice returns a copy of a portion of the array. ' + - 'splice removes/replaces elements in place.', - task: 'Extract and modify arrays.', - hint: 'const portion = arr.slice(1, 3)', + "slice returns a copy of a portion of the array. " + + "splice removes/replaces elements in place.", + task: "Extract and modify arrays.", + hint: "const portion = arr.slice(1, 3)", starterCode: `const numbers = [0, 1, 2, 3, 4, 5] const portion = numbers.slice(1, 4) @@ -4409,13 +4403,11 @@ console.log("After insert:", arr2)`, }, { id: 117, - title: 'Array Methods - flat', - level: 'medium', - content: - 'flat flattens nested arrays. ' + - 'flatMap combines map and flat in one operation.', - task: 'Flatten nested arrays.', - hint: 'const flat = nested.flat()', + title: "Array Methods - flat", + level: "medium", + content: "flat flattens nested arrays. " + "flatMap combines map and flat in one operation.", + task: "Flatten nested arrays.", + hint: "const flat = nested.flat()", starterCode: `const nested = [1, [2, 3], [4, [5, 6]]] const flat1 = nested.flat() @@ -4437,12 +4429,12 @@ console.log("Doubled + 1:", doubledAndPlusOne)`, }, { id: 118, - title: 'String Methods', - level: 'medium', + title: "String Methods", + level: "medium", content: - 'Strings have useful methods like split, join, trim, etc. ' + - 'TypeScript treats them as string methods.', - task: 'Manipulate a string.', + "Strings have useful methods like split, join, trim, etc. " + + "TypeScript treats them as string methods.", + task: "Manipulate a string.", hint: "str.split(',').join('-')", starterCode: `const text = " Hello, World! " @@ -4466,13 +4458,13 @@ console.log("Slice:", email.slice(0, 4))`, }, { id: 119, - title: 'Math and Number', - level: 'medium', + title: "Math and Number", + level: "medium", content: - 'Math provides useful mathematical functions. ' + - 'Number has constants and methods for conversion.', - task: 'Use Math and Number for operations.', - hint: 'Math.floor(Math.random() * 10)', + "Math provides useful mathematical functions. " + + "Number has constants and methods for conversion.", + task: "Use Math and Number for operations.", + hint: "Math.floor(Math.random() * 10)", starterCode: `console.log("Round:", Math.round(4.5)) console.log("Floor:", Math.floor(4.9)) console.log("Ceil:", Math.ceil(4.1)) @@ -4493,13 +4485,11 @@ console.log("IsFinite:", Number.isFinite(Infinity))`, }, { id: 120, - title: 'Date', - level: 'medium', - content: - 'Date represents dates and times. ' + - 'Methods get individual components.', - task: 'Work with dates.', - hint: 'const now = new Date()', + title: "Date", + level: "medium", + content: "Date represents dates and times. " + "Methods get individual components.", + task: "Work with dates.", + hint: "const now = new Date()", starterCode: `const now = new Date() console.log("Now:", now) console.log("ISO:", now.toISOString()) @@ -4520,13 +4510,12 @@ console.log("After week:", afterWeek.toDateString())`, }, { id: 121, - title: 'JSON parse and stringify', - level: 'medium', + title: "JSON parse and stringify", + level: "medium", content: - 'JSON.stringify converts objects to string. ' + - 'JSON.parse converts string to object.', - task: 'Serialize and deserialize JSON.', - hint: 'JSON.parse(jsonString)', + "JSON.stringify converts objects to string. " + "JSON.parse converts string to object.", + task: "Serialize and deserialize JSON.", + hint: "JSON.parse(jsonString)", starterCode: `const obj = { name: "Alice", age: 25, @@ -4548,13 +4537,13 @@ console.log("User:", user.name)`, }, { id: 122, - title: 'Promise.all and Promise.race', - level: 'medium', + title: "Promise.all and Promise.race", + level: "medium", content: - 'Promise.all waits for all promises to resolve. ' + - 'Promise.race returns the first one to resolve.', - task: 'Work with multiple promises.', - hint: 'Promise.all([p1, p2])', + "Promise.all waits for all promises to resolve. " + + "Promise.race returns the first one to resolve.", + task: "Work with multiple promises.", + hint: "Promise.all([p1, p2])", starterCode: `const p1 = Promise.resolve(1) const p2 = Promise.resolve(2) const p3 = Promise.resolve(3) @@ -4579,13 +4568,13 @@ Promise.allSettled([fail, success]).then(results => { }, { id: 123, - title: 'try/catch/finally', - level: 'medium', + title: "try/catch/finally", + level: "medium", content: - 'try executes code, catch handles errors, finally always executes. ' + - 'TypeScript infers the error type as unknown.', - task: 'Handle errors with try/catch.', - hint: 'try { } catch (e) { }', + "try executes code, catch handles errors, finally always executes. " + + "TypeScript infers the error type as unknown.", + task: "Handle errors with try/catch.", + hint: "try { } catch (e) { }", starterCode: `function divide(a: number, b: number): number { if (b === 0) throw new Error("Division by zero") return a / b @@ -4613,11 +4602,10 @@ console.log(safeParse("invalid"))`, }, { id: 124, - title: 'throw and Error', - level: 'medium', - content: - 'throw throws exceptions. ' + 'The Error type has message and name.', - task: 'Throw custom errors.', + title: "throw and Error", + level: "medium", + content: "throw throws exceptions. " + "The Error type has message and name.", + task: "Throw custom errors.", hint: "throw new Error('message')", starterCode: `function validateAge(age: number): void { if (age < 0) { @@ -4649,13 +4637,11 @@ try { }, { id: 125, - title: 'setTimeout and setInterval', - level: 'medium', - content: - 'setTimeout executes after a delay. ' + - 'setInterval executes repeatedly.', - task: 'Schedule code execution.', - hint: 'setTimeout(() => {}, 1000)', + title: "setTimeout and setInterval", + level: "medium", + content: "setTimeout executes after a delay. " + "setInterval executes repeatedly.", + task: "Schedule code execution.", + hint: "setTimeout(() => {}, 1000)", starterCode: `console.log("Before timeout") setTimeout(() => { @@ -4676,13 +4662,11 @@ const interval = setInterval(() => { }, { id: 126, - title: 'clearTimeout and clearInterval', - level: 'medium', - content: - 'clearTimeout cancels a setTimeout. ' + - 'clearInterval stops a setInterval.', - task: 'Cancel timers.', - hint: 'clearTimeout(timerId)', + title: "clearTimeout and clearInterval", + level: "medium", + content: "clearTimeout cancels a setTimeout. " + "clearInterval stops a setInterval.", + task: "Cancel timers.", + hint: "clearTimeout(timerId)", starterCode: `const timeoutId = setTimeout(() => { console.log("This won't print") }, 1000) @@ -4703,13 +4687,12 @@ const intervalId = setInterval(() => { }, { id: 127, - title: 'Object.keys, values, entries', - level: 'medium', + title: "Object.keys, values, entries", + level: "medium", content: - 'Object.keys returns keys, values returns values, ' + - 'entries returns [key, value] pairs.', - task: 'Iterate over object properties.', - hint: 'Object.keys(obj)', + "Object.keys returns keys, values returns values, " + "entries returns [key, value] pairs.", + task: "Iterate over object properties.", + hint: "Object.keys(obj)", starterCode: `const user = { name: "Alice", age: 25, @@ -4730,13 +4713,13 @@ Object.entries(user).forEach(([key, value]) => { }, { id: 128, - title: 'Object.assign', - level: 'medium', + title: "Object.assign", + level: "medium", content: - 'Object.assign copies properties from source objects to a destination. ' + - 'Similar to the spread operator.', - task: 'Copy properties between objects.', - hint: 'Object.assign(target, source)', + "Object.assign copies properties from source objects to a destination. " + + "Similar to the spread operator.", + task: "Copy properties between objects.", + hint: "Object.assign(target, source)", starterCode: `const target = { a: 1 } const source = { b: 2, c: 3 } @@ -4755,13 +4738,13 @@ console.log("Clone:", clone)`, }, { id: 129, - title: 'Object.freeze and seal', - level: 'medium', + title: "Object.freeze and seal", + level: "medium", content: - 'Object.freeze prevents adding/modifying properties. ' + - 'Object.seal prevents adding but allows modification.', - task: 'Make an object immutable.', - hint: 'Object.freeze(obj)', + "Object.freeze prevents adding/modifying properties. " + + "Object.seal prevents adding but allows modification.", + task: "Make an object immutable.", + hint: "Object.freeze(obj)", starterCode: `const obj = { name: "Alice", age: 25 } Object.freeze(obj) @@ -4787,13 +4770,11 @@ console.log("Sealed new prop:", sealed.newProp)`, }, { id: 130, - title: 'Array.isArray', - level: 'medium', - content: - 'Array.isArray checks if a value is an array. ' + - 'Useful for type guards.', - task: 'Check if something is an array.', - hint: 'Array.isArray(value)', + title: "Array.isArray", + level: "medium", + content: "Array.isArray checks if a value is an array. " + "Useful for type guards.", + task: "Check if something is an array.", + hint: "Array.isArray(value)", starterCode: `console.log("Is array:", Array.isArray([1, 2, 3])) console.log("Not array:", Array.isArray("hello")) console.log("Not array:", Array.isArray({ length: 3 })) @@ -4813,13 +4794,13 @@ process({ 0: "a", 1: "b", length: 2 })`, }, { id: 131, - title: 'Boolean Coercion', - level: 'medium', + title: "Boolean Coercion", + level: "medium", content: - 'Values can be converted to boolean with !! or Boolean(). ' + + "Values can be converted to boolean with !! or Boolean(). " + 'Understand falsy values: false, 0, "", null, undefined, NaN.', - task: 'Convert values to boolean.', - hint: 'const bool = !!value', + task: "Convert values to boolean.", + hint: "const bool = !!value", starterCode: `console.log("Boolean of 1:", Boolean(1)) console.log("Boolean of 0:", Boolean(0)) console.log("Boolean of '':", Boolean("")) @@ -4838,12 +4819,12 @@ console.log("Bool:", bool)`, }, { id: 132, - title: 'Number Coercion', - level: 'medium', + title: "Number Coercion", + level: "medium", content: - 'Convert strings to numbers with Number(), parseInt(), parseFloat(). ' + - 'Understand the difference between them.', - task: 'Convert strings to numbers.', + "Convert strings to numbers with Number(), parseInt(), parseFloat(). " + + "Understand the difference between them.", + task: "Convert strings to numbers.", hint: "Number('42') or parseInt('42')", starterCode: `console.log("Number('42'):", Number("42")) console.log("Number('3.14'):", Number("3.14")) @@ -4863,12 +4844,12 @@ console.log("+ '3.14':", +"3.14")`, }, { id: 133, - title: 'String Coercion', - level: 'medium', + title: "String Coercion", + level: "medium", content: - 'Convert values to string with String() or toString(). ' + - 'Template literals also convert automatically.', - task: 'Convert values to string.', + "Convert values to string with String() or toString(). " + + "Template literals also convert automatically.", + task: "Convert values to string.", hint: "String(42) or 42 + ''", starterCode: `console.log("String(42):", String(42)) console.log("String(true):", String(true)) @@ -4888,13 +4869,13 @@ console.log("\`Bool: \${bool}\`:", \`Bool: \${bool}\`)`, }, { id: 134, - title: 'Default Parameters', - level: 'medium', + title: "Default Parameters", + level: "medium", content: - 'Parameters with default values are used when the argument is undefined. ' + - 'Different from optional (?), which can be omitted completely.', - task: 'Use parameters with default values.', - hint: 'function fn(a: number = 10)', + "Parameters with default values are used when the argument is undefined. " + + "Different from optional (?), which can be omitted completely.", + task: "Use parameters with default values.", + hint: "function fn(a: number = 10)", starterCode: `function greet(name: string = "World"): string { return \`Hello, \${name}!\` } @@ -4918,13 +4899,13 @@ console.log(createUser("Charlie", 25))`, }, { id: 135, - title: 'Rest Parameters', - level: 'medium', + title: "Rest Parameters", + level: "medium", content: - 'Rest parameters collect multiple arguments into an array. ' + - 'Useful for functions with variable number of parameters.', - task: 'Create a function with rest parameters.', - hint: 'function fn(...args: number[])', + "Rest parameters collect multiple arguments into an array. " + + "Useful for functions with variable number of parameters.", + task: "Create a function with rest parameters.", + hint: "function fn(...args: number[])", starterCode: `function sum(...numbers: number[]): number { return numbers.reduce((a, b) => a + b, 0) } @@ -4944,13 +4925,13 @@ console.log("Spread:", sum(...arr))`, }, { id: 136, - title: 'Arguments Object', - level: 'medium', + title: "Arguments Object", + level: "medium", content: - 'arguments is an array-like object available in regular functions. ' + + "arguments is an array-like object available in regular functions. " + "Arrow functions don't have arguments.", - task: 'Access arguments via arguments.', - hint: 'function fn() { console.log(arguments) }', + task: "Access arguments via arguments.", + hint: "function fn() { console.log(arguments) }", starterCode: `function sum(): number { let total = 0 for (let i = 0; i < arguments.length; i++) { @@ -4970,13 +4951,12 @@ showArgs(1, "hello", true)`, }, { id: 137, - title: 'IIFE - Immediately Invoked Function', - level: 'medium', + title: "IIFE - Immediately Invoked Function", + level: "medium", content: - 'IIFE is a function that executes immediately. ' + - 'Useful for creating private scope.', - task: 'Create an IIFE.', - hint: '(() => { })()', + "IIFE is a function that executes immediately. " + "Useful for creating private scope.", + task: "Create an IIFE.", + hint: "(() => { })()", starterCode: `(function() { const privateVar = "I'm private" console.log("IIFE executed:", privateVar) @@ -5004,13 +4984,13 @@ console.log("Counter:", counter.get())`, }, { id: 138, - title: 'Callback Functions', - level: 'medium', + title: "Callback Functions", + level: "medium", content: - 'Callbacks are functions passed as arguments to other functions. ' + - 'Commonly used in event listeners and array methods.', - task: 'Pass a function as a callback.', - hint: 'arr.forEach((item) => { })', + "Callbacks are functions passed as arguments to other functions. " + + "Commonly used in event listeners and array methods.", + task: "Pass a function as a callback.", + hint: "arr.forEach((item) => { })", starterCode: `function processArray( arr: number[], callback: (n: number) => number @@ -5044,13 +5024,11 @@ withCallback("Alice", (err, result) => { }, { id: 139, - title: 'for...in and for...of', - level: 'medium', - content: - 'for...in iterates over object keys. ' + - 'for...of iterates over values of iterables.', - task: 'Iterate over objects and arrays.', - hint: 'for...of for arrays', + title: "for...in and for...of", + level: "medium", + content: "for...in iterates over object keys. " + "for...of iterates over values of iterables.", + task: "Iterate over objects and arrays.", + hint: "for...of for arrays", starterCode: `const user = { name: "Alice", age: 25, city: "SP" } console.log("for...in:") @@ -5072,13 +5050,11 @@ for (const [index, num] of numbers.entries()) { }, { id: 140, - title: 'while and do...while', - level: 'medium', - content: - 'while executes while the condition is true. ' + - 'do...while executes at least once.', - task: 'Use while loops.', - hint: 'while (condition) { }', + title: "while and do...while", + level: "medium", + content: "while executes while the condition is true. " + "do...while executes at least once.", + task: "Use while loops.", + hint: "while (condition) { }", starterCode: `let count = 0 while (count < 5) { @@ -5108,13 +5084,11 @@ console.log("Length:", chars)`, }, { id: 141, - title: 'break and continue', - level: 'medium', - content: - 'break exits the loop completely. ' + - 'continue skips to the next iteration.', - task: 'Control loop flow.', - hint: 'break to exit, continue to skip', + title: "break and continue", + level: "medium", + content: "break exits the loop completely. " + "continue skips to the next iteration.", + task: "Control loop flow.", + hint: "break to exit, continue to skip", starterCode: `for (let i = 1; i <= 10; i++) { if (i === 5) break console.log("i:", i) @@ -5140,12 +5114,11 @@ console.log("Found:", found)`, }, { id: 142, - title: 'Labeled Statements', - level: 'medium', - content: - 'Labels identify loops for break/continue. ' + 'Useful for nested loops.', - task: 'Use labels to control nested loops.', - hint: 'label: for (...)', + title: "Labeled Statements", + level: "medium", + content: "Labels identify loops for break/continue. " + "Useful for nested loops.", + task: "Use labels to control nested loops.", + hint: "label: for (...)", starterCode: `outer: for (let i = 1; i <= 3; i++) { for (let j = 1; j <= 3; j++) { console.log(\`i=\${i}, j=\${j}\`) @@ -5169,12 +5142,10 @@ outer2: while (i < 3) { }, { id: 143, - title: 'typeof operator', - level: 'medium', - content: - 'typeof returns the type of a value as a string. ' + - 'Useful for basic type guards.', - task: 'Use typeof to check types.', + title: "typeof operator", + level: "medium", + content: "typeof returns the type of a value as a string. " + "Useful for basic type guards.", + task: "Use typeof to check types.", hint: "typeof value === 'string'", starterCode: `console.log("typeof 'hello':", typeof "hello") console.log("typeof 42:", typeof 42) @@ -5197,13 +5168,13 @@ console.log(process(42))`, }, { id: 144, - title: 'instanceof', - level: 'medium', + title: "instanceof", + level: "medium", content: - 'instanceof checks if an object is an instance of a class. ' + - 'Also works for built-in objects like Array, Date.', - task: 'Use instanceof to check classes.', - hint: 'value instanceof Array', + "instanceof checks if an object is an instance of a class. " + + "Also works for built-in objects like Array, Date.", + task: "Use instanceof to check classes.", + hint: "value instanceof Array", starterCode: `class Dog { bark() { return "Woof!" } } @@ -5234,12 +5205,12 @@ process([1, 2, 3])`, }, { id: 145, - title: 'in operator', - level: 'medium', + title: "in operator", + level: "medium", content: - 'in checks if a property exists in an object. ' + - 'Returns true for own and inherited (use hasOwnProperty for own only).', - task: 'Use in to check properties.', + "in checks if a property exists in an object. " + + "Returns true for own and inherited (use hasOwnProperty for own only).", + task: "Use in to check properties.", hint: "'prop' in object", starterCode: `const user = { name: "Alice", age: 25 } @@ -5268,13 +5239,12 @@ console.log(hasProp(car, "year"))`, }, { id: 146, - title: 'delete operator', - level: 'medium', + title: "delete operator", + level: "medium", content: - 'delete removes properties from objects. ' + - 'Does not work on variables or functions.', - task: 'Remove properties from objects.', - hint: 'delete object.property', + "delete removes properties from objects. " + "Does not work on variables or functions.", + task: "Remove properties from objects.", + hint: "delete object.property", starterCode: `const user = { name: "Alice", age: 25, city: "SP" } console.log("Before delete:", user) @@ -5292,13 +5262,13 @@ console.log("'2' in arr:", "2" in arr)`, }, { id: 147, - title: 'void operator', - level: 'medium', + title: "void operator", + level: "medium", content: - 'void evaluates an expression and returns undefined. ' + - 'Useful for IIFEs or preventing navigation in links.', - task: 'Use void operator.', - hint: 'void expression', + "void evaluates an expression and returns undefined. " + + "Useful for IIFEs or preventing navigation in links.", + task: "Use void operator.", + hint: "void expression", starterCode: `console.log("void 0:", void 0) console.log("void 1+1:", void 1 + 1) @@ -5318,13 +5288,13 @@ console.log("Use void for preventDefault")`, }, { id: 148, - title: 'Comma Operator', - level: 'medium', + title: "Comma Operator", + level: "medium", content: - 'The comma evaluates expressions from left to right and returns the last one. ' + - 'Useful in for loops and compact expressions.', - task: 'Use comma operator.', - hint: '(a, b, c) - returns c', + "The comma evaluates expressions from left to right and returns the last one. " + + "Useful in for loops and compact expressions.", + task: "Use comma operator.", + hint: "(a, b, c) - returns c", starterCode: `const result = (1, 2, 3) console.log("Result:", result) @@ -5342,13 +5312,13 @@ console.log("Coords:", coords)`, }, { id: 149, - title: 'Bitwise Operators', - level: 'medium', + title: "Bitwise Operators", + level: "medium", content: - 'Bitwise operators manipulate bits of numbers. ' + - 'Useful for flags, encryption, optimization.', - task: 'Use bitwise operators.', - hint: '& | ^ ~ << >>', + "Bitwise operators manipulate bits of numbers. " + + "Useful for flags, encryption, optimization.", + task: "Use bitwise operators.", + hint: "& | ^ ~ << >>", starterCode: `console.log("5 & 3:", 5 & 3) console.log("5 | 3:", 5 | 3) console.log("5 ^ 3:", 5 ^ 3) @@ -5375,12 +5345,12 @@ console.log("After removing A:", flags)`, }, { id: 150, - title: 'eval', - level: 'medium', + title: "eval", + level: "medium", content: - 'eval executes a string as JavaScript code. ' + - 'Avoid using in production code for security.', - task: 'Use eval carefully.', + "eval executes a string as JavaScript code. " + + "Avoid using in production code for security.", + task: "Use eval carefully.", hint: "eval('code string')", starterCode: `const code = "2 + 2" console.log("Result:", eval(code)) diff --git a/src/data/lessons/lessons.ts b/src/data/lessons/lessons.ts index 393caf0..4392db0 100644 --- a/src/data/lessons/lessons.ts +++ b/src/data/lessons/lessons.ts @@ -1,18 +1,18 @@ -import type { Lesson } from './types'; -export type { Level, Lesson } from './types'; +import type { Lesson } from "./types"; +export type { Level, Lesson } from "./types"; export const lessons: Lesson[] = [ { id: 1, - title: 'Bem-vindo ao TypeScript', - level: 'basic', + title: "Bem-vindo ao TypeScript", + level: "basic", content: - 'TypeScript é um superconjunto de JavaScript que adiciona tipagem estática. ' + + "TypeScript é um superconjunto de JavaScript que adiciona tipagem estática. " + 'Com ele, você define o "formato" dos seus dados usando interfaces, evitando ' + - 'erros em tempo de execução. Veja o exemplo: criamos uma interface `User` com ' + - 'dois campos tipados e instanciamos um objeto que a respeita.', + "erros em tempo de execução. Veja o exemplo: criamos uma interface `User` com " + + "dois campos tipados e instanciamos um objeto que a respeita.", task: "Altere o nome do usuário de 'TypeScript Explorer' para outro nome qualquer.", - hint: 'Mude o valor de `name` dentro do objeto `user`.', + hint: "Mude o valor de `name` dentro do objeto `user`.", starterCode: `interface User { name: string; id: number; @@ -27,14 +27,14 @@ console.log(\`Olá, \${user.name}! Seu ID é \${user.id}.\`);`, }, { id: 2, - title: 'Tipagem Estática e Inferência', - level: 'basic', - content: - 'TypeScript infere tipos automaticamente em muitos casos. Quando você define uma variável ' + - 'com um valor inicial, TypeScript deduz seu tipo. Isso é chamado de inferência de tipo e ' + - 'torna o código mais conciso enquanto mantém a segurança.', - task: 'Observe como o TypeScript infere o tipo da variável `message`.', - hint: 'O tipo é inferido a partir do valor inicial.', + title: "Tipagem Estática e Inferência", + level: "basic", + content: + "TypeScript infere tipos automaticamente em muitos casos. Quando você define uma variável " + + "com um valor inicial, TypeScript deduz seu tipo. Isso é chamado de inferência de tipo e " + + "torna o código mais conciso enquanto mantém a segurança.", + task: "Observe como o TypeScript infere o tipo da variável `message`.", + hint: "O tipo é inferido a partir do valor inicial.", starterCode: `let message = "Hello, TypeScript!" let count = 42 let isActive = true @@ -50,13 +50,13 @@ console.log(isActive)`, }, { id: 3, - title: 'Interfaces', - level: 'basic', + title: "Interfaces", + level: "basic", content: - 'Interfaces definem a estrutura que objetos devem seguir. São fundamentais em TypeScript ' + - 'para garantir que objetos tenham as propriedades corretas com os tipos certos.', - task: 'Adicione uma propriedade `email` à interface `Person` e ao objeto.', - hint: 'Adicione `email: string` na interface.', + "Interfaces definem a estrutura que objetos devem seguir. São fundamentais em TypeScript " + + "para garantir que objetos tenham as propriedades corretas com os tipos certos.", + task: "Adicione uma propriedade `email` à interface `Person` e ao objeto.", + hint: "Adicione `email: string` na interface.", starterCode: `interface Person { name: string age: number @@ -71,13 +71,13 @@ console.log(\`\${person.name} tem \${person.age} anos\`)`, }, { id: 4, - title: 'Enums', - level: 'basic', + title: "Enums", + level: "basic", content: - 'Enums permitem definir um conjunto de constantes nomeadas. São úteis para ' + - 'representar estados, direções, papéis de usuário, etc. TypeScript suporta ' + - 'enums numéricos (padrão) e de string.', - task: 'Adicione um valor `ADMIN` ao enum `Role` e crie um usuário com esse papel.', + "Enums permitem definir um conjunto de constantes nomeadas. São úteis para " + + "representar estados, direções, papéis de usuário, etc. TypeScript suporta " + + "enums numéricos (padrão) e de string.", + task: "Adicione um valor `ADMIN` ao enum `Role` e crie um usuário com esse papel.", hint: 'Adicione `ADMIN = "ADMIN"` ao enum e use `Role.ADMIN` no objeto.', starterCode: `enum Direction { UP = "UP", @@ -107,14 +107,14 @@ console.log(\`\${player.name} (\${player.role}) está olhando para \${player.fac }, { id: 5, - title: 'Type Aliases e Union Types', - level: 'basic', - content: - 'Type aliases criam nomes para tipos complexos. Union types (`|`) permitem ' + - 'que uma variável aceite mais de um tipo. Isso é muito mais seguro do que usar ' + - '`any` e ainda mantém a flexibilidade.', - task: 'Crie um type alias `Result` que seja `string | number | boolean`.', - hint: 'type Result = string | number | boolean;', + title: "Type Aliases e Union Types", + level: "basic", + content: + "Type aliases criam nomes para tipos complexos. Union types (`|`) permitem " + + "que uma variável aceite mais de um tipo. Isso é muito mais seguro do que usar " + + "`any` e ainda mantém a flexibilidade.", + task: "Crie um type alias `Result` que seja `string | number | boolean`.", + hint: "type Result = string | number | boolean;", starterCode: `type ID = string | number type Status = "active" | "inactive" | "pending" @@ -137,14 +137,14 @@ console.log(getStatusLabel("active"))`, }, { id: 6, - title: 'Type Assertions', - level: 'basic', + title: "Type Assertions", + level: "basic", content: - 'Type assertions dizem ao TypeScript para tratar um valor como um tipo específico. ' + + "Type assertions dizem ao TypeScript para tratar um valor como um tipo específico. " + 'Use `as` ou sintaxe de colchete angular. É como um "cast" em outras linguagens, ' + - 'mas não converte o valor em tempo de execução.', - task: 'Use type assertion para tratar `input` como `string`.', - hint: 'const str = input as string;', + "mas não converte o valor em tempo de execução.", + task: "Use type assertion para tratar `input` como `string`.", + hint: "const str = input as string;", starterCode: `let input: unknown = "hello world" const length1 = (input as string).length @@ -155,15 +155,15 @@ console.log("Length 2:", length2)`, }, { id: 7, - title: 'Tipos Básicos', - level: 'basic', + title: "Tipos Básicos", + level: "basic", content: - 'TypeScript suporta todos os tipos primitivos do JavaScript: `string`, `number`, ' + - '`boolean`, `null`, `undefined`. Além disso, oferece `symbol`, `bigint` e o ' + - 'tipo `void` para funções que não retornam nada.', - task: 'Crie variáveis dos tipos aprendidos.', + "TypeScript suporta todos os tipos primitivos do JavaScript: `string`, `number`, " + + "`boolean`, `null`, `undefined`. Além disso, oferece `symbol`, `bigint` e o " + + "tipo `void` para funções que não retornam nada.", + task: "Crie variáveis dos tipos aprendidos.", hint: 'let name: string = "Alice";', - starterCode: `{let name: string = "Alice" + starterCode: `let name: string = "Alice" let age: number = 25 let isStudent: boolean = true let nothing: null = null @@ -171,16 +171,16 @@ let notDefined: undefined = undefined let id: symbol = Symbol("id") let bigNumber: bigint = 9007199254740991n -console.log(name, age, isStudent)}`, +console.log(name, age, isStudent)`, }, { id: 8, - title: 'Arrays e Tuplas', - level: 'basic', + title: "Arrays e Tuplas", + level: "basic", content: - 'Arrays em TypeScript podem ser tipados como `number[]` ou `Array`. ' + - 'Tuplas são arrays com tamanho fixo e tipos específicos em cada posição: `[string, number]`.', - task: 'Crie uma tupla com o nome e idade de uma pessoa.', + "Arrays em TypeScript podem ser tipados como `number[]` ou `Array`. " + + "Tuplas são arrays com tamanho fixo e tipos específicos em cada posição: `[string, number]`.", + task: "Crie uma tupla com o nome e idade de uma pessoa.", hint: 'let person: [string, number] = ["Alice", 25];', starterCode: `const numbers: number[] = [1, 2, 3, 4, 5] const names: Array = ["Alice", "Bob", "Charlie"] @@ -194,13 +194,13 @@ console.log("Coords:", coords)`, }, { id: 9, - title: 'Funções - Tipagem de Parâmetros e Retorno', - level: 'basic', + title: "Funções - Tipagem de Parâmetros e Retorno", + level: "basic", content: - 'Funções em TypeScript podem ter tipos definidos para parâmetros e retorno. ' + - 'Isso garante que a função seja chamada com os argumentos corretos e retorne o valor esperado.', - task: 'Adicione o tipo de retorno `number` à função `soma`.', - hint: 'function soma(a: number, b: number): number', + "Funções em TypeScript podem ter tipos definidos para parâmetros e retorno. " + + "Isso garante que a função seja chamada com os argumentos corretos e retorne o valor esperado.", + task: "Adicione o tipo de retorno `number` à função `soma`.", + hint: "function soma(a: number, b: number): number", starterCode: `function greet(name: string): string { return \`Olá, \${name}!\` } @@ -217,14 +217,14 @@ console.log(add(10, 20))`, }, { id: 10, - title: 'Parâmetros Opcionais e Default', - level: 'basic', - content: - 'Parâmetros opcionais usam `?` (ex: `name?: string`). Parâmetros com valor padrão ' + - 'são automaticamente opcionais. A diferença é que `undefined` é passado para opcionais, ' + - 'enquanto o valor default é usado para parâmetros com默认值.', - task: 'Torne o parâmetro `age` opcional na função `introduce`.', - hint: 'function introduce(name: string, age?: number)', + title: "Parâmetros Opcionais e Default", + level: "basic", + content: + "Parâmetros opcionais usam `?` (ex: `name?: string`). Parâmetros com valor padrão " + + "são automaticamente opcionais. A diferença é que `undefined` é passado para opcionais, " + + "enquanto o valor default é usado para parâmetros com默认值.", + task: "Torne o parâmetro `age` opcional na função `introduce`.", + hint: "function introduce(name: string, age?: number)", starterCode: `function greet(name: string, greeting?: string): string { return greeting ? \`\${greeting}, \${name}!\` : \`Olá, \${name}!\` } @@ -243,12 +243,12 @@ console.log(introduce("Diana"))`, }, { id: 11, - title: 'Utility Types - Partial, Required, Pick, Omit', - level: 'advanced', + title: "Utility Types - Partial, Required, Pick, Omit", + level: "advanced", content: - 'TypeScript inclui utility types embutidos que transformam tipos existentes: ' + - '`Partial` torna todos os campos opcionais, `Required` os torna obrigatórios, ' + - '`Pick` seleciona campos, `Omit` remove campos.', + "TypeScript inclui utility types embutidos que transformam tipos existentes: " + + "`Partial` torna todos os campos opcionais, `Required` os torna obrigatórios, " + + "`Pick` seleciona campos, `Omit` remove campos.", task: 'Use `Omit` para criar um tipo `PublicUser`.', hint: 'type PublicUser = Omit', starterCode: `interface User { @@ -276,14 +276,14 @@ console.log("Preview:", JSON.stringify(preview))`, }, { id: 12, - title: 'Mapped Types', - level: 'advanced', - content: - 'Mapped types permitem criar novos tipos transformando cada propriedade de um tipo existente. ' + - 'Usam a sintaxe `{ [K in keyof T]: ... }`. Combinados com `keyof` e modificadores ' + - '(`readonly`, `?`), são extremamente poderosos.', - task: 'Crie um mapped type `Nullable` que torne todas as propriedades opcionais.', - hint: 'type Nullable = { [K in keyof T]?: T[K] | null; }', + title: "Mapped Types", + level: "advanced", + content: + "Mapped types permitem criar novos tipos transformando cada propriedade de um tipo existente. " + + "Usam a sintaxe `{ [K in keyof T]: ... }`. Combinados com `keyof` e modificadores " + + "(`readonly`, `?`), são extremamente poderosos.", + task: "Crie um mapped type `Nullable` que torne todas as propriedades opcionais.", + hint: "type Nullable = { [K in keyof T]?: T[K] | null; }", starterCode: `interface Config { host: string port: number @@ -309,14 +309,14 @@ console.log("Partial:", JSON.stringify(partial))`, }, { id: 13, - title: 'Conditional Types', - level: 'advanced', - content: - 'Conditional types seguem a sintaxe `T extends U ? X : Y` — se `T` é atribuível a `U`, ' + - 'o tipo resultante é `X`, caso contrário `Y`. Com `infer`, você pode extrair tipos ' + - 'de dentro de outros tipos.', - task: 'Crie um conditional type `IsArray` que retorne `true` se T for array.', - hint: 'type IsArray = T extends any[] ? true : false', + title: "Conditional Types", + level: "advanced", + content: + "Conditional types seguem a sintaxe `T extends U ? X : Y` — se `T` é atribuível a `U`, " + + "o tipo resultante é `X`, caso contrário `Y`. Com `infer`, você pode extrair tipos " + + "de dentro de outros tipos.", + task: "Crie um conditional type `IsArray` que retorne `true` se T for array.", + hint: "type IsArray = T extends any[] ? true : false", starterCode: `type IsString = T extends string ? "yes" : "no" type A = IsString @@ -340,14 +340,14 @@ console.log("Result:", JSON.stringify(result))`, }, { id: 14, - title: 'Decorators', - level: 'advanced', - content: - 'Decorators são funções especiais que podem ser aplicadas a classes, métodos, ' + - 'propriedades e parâmetros usando a sintaxe `@decorator`. São amplamente usados ' + - 'em frameworks como Angular, NestJS e TypeORM.', - task: 'Crie um decorator `@readonly` que torne uma propriedade não-editável.', - hint: 'Use Object.defineProperty no descriptor.', + title: "Decorators", + level: "advanced", + content: + "Decorators são funções especiais que podem ser aplicadas a classes, métodos, " + + "propriedades e parâmetros usando a sintaxe `@decorator`. São amplamente usados " + + "em frameworks como Angular, NestJS e TypeORM.", + task: "Crie um decorator `@readonly` que torne uma propriedade não-editável.", + hint: "Use Object.defineProperty no descriptor.", starterCode: `function sealed(constructor: Function) { Object.seal(constructor) Object.seal(constructor.prototype) @@ -381,14 +381,14 @@ console.log("Fib(10):", calc.fibonacci(10))`, }, { id: 15, - title: 'Generics - Introdução', - level: 'basic', - content: - 'Generics permitem criar componentes que funcionam com qualquer tipo, mantendo ' + - 'a segurança de tipos. São representados por `` e permitem criar funções, ' + - 'classes e interfaces reutilizáveis.', - task: 'Crie uma função `identity` que retorne o mesmo valor passado.', - hint: 'function identity(value: T): T { return value; }', + title: "Generics - Introdução", + level: "basic", + content: + "Generics permitem criar componentes que funcionam com qualquer tipo, mantendo " + + "a segurança de tipos. São representados por `` e permitem criar funções, " + + "classes e interfaces reutilizáveis.", + task: "Crie uma função `identity` que retorne o mesmo valor passado.", + hint: "function identity(value: T): T { return value; }", starterCode: `function identity(value: T): T { return value } @@ -401,11 +401,11 @@ console.log(str, num, auto)`, }, { id: 16, - title: 'Tipos Literais', - level: 'basic', + title: "Tipos Literais", + level: "basic", content: - 'TypeScript permite especificar valores exatos que uma variável pode ter usando tipos literais. ' + - 'Isso é útil quando você quer restringir um valor a um conjunto específico de strings ou números.', + "TypeScript permite especificar valores exatos que uma variável pode ter usando tipos literais. " + + "Isso é útil quando você quer restringir um valor a um conjunto específico de strings ou números.", task: "Crie uma variável que possa ter apenas os valores 'pending', 'loading' ou 'success'.", hint: "type Status = 'pending' | 'loading' | 'success';", starterCode: `type Status = "pending" | "loading" | "success" @@ -417,13 +417,13 @@ console.log("Status atual:", currentStatus)`, }, { id: 17, - title: 'Funções Sobrescritas (Overloads)', - level: 'basic', + title: "Funções Sobrescritas (Overloads)", + level: "basic", content: - 'TypeScript suporta sobrescrita de funções, permitindo que você defina múltiplas assinaturas. ' + - 'O TypeScript escolhe a assinatura correta com base nos argumentos fornecidos.', - task: 'Crie uma função `format` que possa formatar números e datas.', - hint: 'Use múltiplas assinaturas antes da implementação.', + "TypeScript suporta sobrescrita de funções, permitindo que você defina múltiplas assinaturas. " + + "O TypeScript escolhe a assinatura correta com base nos argumentos fornecidos.", + task: "Crie uma função `format` que possa formatar números e datas.", + hint: "Use múltiplas assinaturas antes da implementação.", starterCode: `function format(value: string): string function format(value: number, decimals?: number): string function format(value: Date): string @@ -446,13 +446,13 @@ console.log(format(new Date()))`, }, { id: 18, - title: 'Módulos e Imports/Exports', - level: 'basic', + title: "Módulos e Imports/Exports", + level: "basic", content: - 'TypeScript dá suporte total ao sistema de módulos ES6. Organize seu código em arquivos ' + - 'separados com importações e exportações explícitas para melhor encapsulamento.', - task: 'Crie e exporte uma função de um módulo, e importe-a em outro.', - hint: 'Use `export` e `import` no padrão ES6.', + "TypeScript dá suporte total ao sistema de módulos ES6. Organize seu código em arquivos " + + "separados com importações e exportações explícitas para melhor encapsulamento.", + task: "Crie e exporte uma função de um módulo, e importe-a em outro.", + hint: "Use `export` e `import` no padrão ES6.", starterCode: `export const capitalize = (str: string): string => { return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase() } @@ -472,13 +472,13 @@ console.log(trim(text))`, }, { id: 19, - title: 'Namespaces', - level: 'basic', + title: "Namespaces", + level: "basic", content: - 'Namespaces agrupam código relacionado sem poluir o escopo global. Use `namespace` ' + - 'para organizar código internamente e `export` para expor membros.', - task: 'Crie um namespace `MathUtils` com funções `add` e `multiply`.', - hint: 'namespace MathUtils { export function add(...) }', + "Namespaces agrupam código relacionado sem poluir o escopo global. Use `namespace` " + + "para organizar código internamente e `export` para expor membros.", + task: "Crie um namespace `MathUtils` com funções `add` e `multiply`.", + hint: "namespace MathUtils { export function add(...) }", starterCode: `namespace MathUtils { export function add(a: number, b: number): number { return a + b @@ -497,13 +497,13 @@ console.log("PI:", MathUtils.PI)`, }, { id: 20, - title: 'Iteradores e Geradores', - level: 'basic', + title: "Iteradores e Geradores", + level: "basic", content: - 'TypeScript dá suporte total aos protocolos iteradores e geradores do ES6. ' + - 'Geradores (`function*`) fornecem uma maneira fácil de criar funções que retornam sequências.', - task: 'Crie uma função geradora que produza números de 1 a N.', - hint: 'Use function* e yield.', + "TypeScript dá suporte total aos protocolos iteradores e geradores do ES6. " + + "Geradores (`function*`) fornecem uma maneira fácil de criar funções que retornam sequências.", + task: "Crie uma função geradora que produza números de 1 a N.", + hint: "Use function* e yield.", starterCode: `function* counter(limit: number) { let count = 1 while (count <= limit) { @@ -522,13 +522,13 @@ console.log("Como array:", nums)`, }, { id: 21, - title: 'Inferência de Tipo Avançada', - level: 'advanced', + title: "Inferência de Tipo Avançada", + level: "advanced", content: - 'TypeScript infere tipos automaticamente em muitos contextos. A inferência funciona ' + - 'em variáveis, parâmetros, retornos e usa análise de fluxo de controle e contextual typing.', - task: 'Observe como o TypeScript infere tipos diferentes no mesmo exemplo.', - hint: 'O tipo de retorno muda baseado no parâmetro.', + "TypeScript infere tipos automaticamente em muitos contextos. A inferência funciona " + + "em variáveis, parâmetros, retornos e usa análise de fluxo de controle e contextual typing.", + task: "Observe como o TypeScript infere tipos diferentes no mesmo exemplo.", + hint: "O tipo de retorno muda baseado no parâmetro.", starterCode: `function processInput(input: string | number) { if (typeof input === "string") { return input.toUpperCase() @@ -548,13 +548,13 @@ console.log("Doubled:", doubled)`, }, { id: 22, - title: 'Compatibilidade Estrutural de Tipos', - level: 'advanced', + title: "Compatibilidade Estrutural de Tipos", + level: "advanced", content: - 'TypeScript usa compatibilidade estrutural — dois tipos são compatíveis se têm a mesma estrutura. ' + - 'Isso é diferente de sistemas nominativos e torna o TypeScript mais flexível.', - task: 'Veja como objetos com estruturas compatíveis podem ser usados interchangeably.', - hint: 'Se as propriedades batem, o tipo é compatível.', + "TypeScript usa compatibilidade estrutural — dois tipos são compatíveis se têm a mesma estrutura. " + + "Isso é diferente de sistemas nominativos e torna o TypeScript mais flexível.", + task: "Veja como objetos com estruturas compatíveis podem ser usados interchangeably.", + hint: "Se as propriedades batem, o tipo é compatível.", starterCode: `interface Point { x: number y: number @@ -579,13 +579,13 @@ console.log("Distance:", distanceFromOrigin(namedPoint))`, }, { id: 23, - title: 'Trabalhando com JavaScript', - level: 'basic', + title: "Trabalhando com JavaScript", + level: "basic", content: - 'TypeScript foi projetado para adotar gradualmente JavaScript existente. ' + - 'Use `@ts-check` ou `checkJs: true` no tsconfig.json para verificar arquivos .js.', - task: 'Entenda como TypeScript verifica código JavaScript.', - hint: 'Use JSDoc para adicionar tipos em arquivos .js.', + "TypeScript foi projetado para adotar gradualmente JavaScript existente. " + + "Use `@ts-check` ou `checkJs: true` no tsconfig.json para verificar arquivos .js.", + task: "Entenda como TypeScript verifica código JavaScript.", + hint: "Use JSDoc para adicionar tipos em arquivos .js.", starterCode: `// Simulando verificação em arquivo .js // Para habilitar: use // @ts-check no topo @@ -611,13 +611,13 @@ console.log("Fatorial de 5:", factorial(5))`, }, { id: 24, - title: 'Arquivos de Declaração (.d.ts)', - level: 'advanced', + title: "Arquivos de Declaração (.d.ts)", + level: "advanced", content: - 'Arquivos de declaração (.d.ts) fornecem informações de tipo para bibliotecas JavaScript. ' + - 'Definições de tipo para bibliotecas populares estão no DefinitelyTyped (@types/*).', - task: 'Crie um arquivo de declaração simples para uma função.', - hint: 'declare function nome(params): returnType;', + "Arquivos de declaração (.d.ts) fornecem informações de tipo para bibliotecas JavaScript. " + + "Definições de tipo para bibliotecas populares estão no DefinitelyTyped (@types/*).", + task: "Crie um arquivo de declaração simples para uma função.", + hint: "declare function nome(params): returnType;", starterCode: `// Simulando um arquivo de declaração declare namespace Utils { @@ -643,12 +643,12 @@ console.log("Instale tipos: npm install @types/lodash")`, }, { id: 25, - title: 'Classes - Introdução', - level: 'basic', + title: "Classes - Introdução", + level: "basic", content: - 'Classes em TypeScript funcionam como em JavaScript moderno, mas com tipagem completa. ' + - 'Você pode definir propriedades, métodos, construtores e modificadores de acesso.', - task: 'Adicione um método `sayHello` à classe `Person`.', + "Classes em TypeScript funcionam como em JavaScript moderno, mas com tipagem completa. " + + "Você pode definir propriedades, métodos, construtores e modificadores de acesso.", + task: "Adicione um método `sayHello` à classe `Person`.", hint: "sayHello() { return 'Olá, ' + this.name; }", starterCode: `class Person { name: string @@ -669,13 +669,13 @@ console.log(person.greet())`, }, { id: 26, - title: 'Modificadores de Acesso', - level: 'basic', + title: "Modificadores de Acesso", + level: "basic", content: - 'TypeScript oferece `public`, `private` e `protected` para controlar o acesso a membros. ' + - 'Também há `readonly` para propriedades que não podem ser alteradas após inicialização.', - task: 'Torne a propriedade `balance` privada e adicione um getter.', - hint: 'private balance: number; public getBalance()', + "TypeScript oferece `public`, `private` e `protected` para controlar o acesso a membros. " + + "Também há `readonly` para propriedades que não podem ser alteradas após inicialização.", + task: "Torne a propriedade `balance` privada e adicione um getter.", + hint: "private balance: number; public getBalance()", starterCode: `class BankAccount { public readonly id: number private balance: number @@ -706,13 +706,13 @@ console.log("New Balance:", account.getBalance())`, }, { id: 27, - title: 'Herança de Classes', - level: 'basic', + title: "Herança de Classes", + level: "basic", content: - 'Classes podem herdar de outras usando `extends`. A classe filha tem acesso a ' + - 'métodos e propriedades públicas/protegidas da classe pai, e pode sobrescrevê-los.', - task: 'Crie uma classe `Student` que herde de `Person`.', - hint: 'class Student extends Person { }', + "Classes podem herdar de outras usando `extends`. A classe filha tem acesso a " + + "métodos e propriedades públicas/protegidas da classe pai, e pode sobrescrevê-los.", + task: "Crie uma classe `Student` que herde de `Person`.", + hint: "class Student extends Person { }", starterCode: `class Person { constructor(public name: string, public age: number) {} @@ -737,13 +737,13 @@ console.log(student.study())`, }, { id: 28, - title: 'Classes Abstratas', - level: 'basic', + title: "Classes Abstratas", + level: "basic", content: - 'Classes abstratas não podem ser instanciadas diretamente, servem como base para outras classes. ' + - 'Podem conter métodos abstratos (sem implementação) que as classes filhas devem implementar.', - task: 'Crie uma classe abstrata `Shape` com método abstrato `area`.', - hint: 'abstract class Shape { abstract area(): number; }', + "Classes abstratas não podem ser instanciadas diretamente, servem como base para outras classes. " + + "Podem conter métodos abstratos (sem implementação) que as classes filhas devem implementar.", + task: "Crie uma classe abstrata `Shape` com método abstrato `area`.", + hint: "abstract class Shape { abstract area(): number; }", starterCode: `abstract class Shape { abstract area(): number abstract perimeter(): number @@ -789,12 +789,12 @@ console.log(circle.describe())`, }, { id: 29, - title: 'Getters e Setters', - level: 'basic', + title: "Getters e Setters", + level: "basic", content: - 'Getters e setters permitem controle preciso sobre o acesso a propriedades. ' + - 'Úteis para validação, computação de valores, ou manter invariantes de classe.', - task: 'Crie um getter `fullName` que retorne nome completo.', + "Getters e setters permitem controle preciso sobre o acesso a propriedades. " + + "Úteis para validação, computação de valores, ou manter invariantes de classe.", + task: "Crie um getter `fullName` que retorne nome completo.", hint: "get fullName(): string { return this.firstName + ' ' + this.lastName; }", starterCode: `class User { private _password: string = "" @@ -828,13 +828,13 @@ console.log("Password:", user.password)`, }, { id: 30, - title: 'Static Members', - level: 'basic', + title: "Static Members", + level: "basic", content: - 'Membros estáticos pertencem à classe em si, não às instâncias. ' + - 'Acessados via `ClassName.property`, são úteis para constantes ou funções utilitárias.', - task: 'Adicione um método estático `createDefault` à classe `User`.', - hint: 'static createDefault(): User { }', + "Membros estáticos pertencem à classe em si, não às instâncias. " + + "Acessados via `ClassName.property`, são úteis para constantes ou funções utilitárias.", + task: "Adicione um método estático `createDefault` à classe `User`.", + hint: "static createDefault(): User { }", starterCode: `class MathHelper { static readonly PI = 3.14159 @@ -854,14 +854,14 @@ console.log("Factorial 5:", MathHelper.factorial(5))`, }, { id: 31, - title: 'Utility Types - Record, Partial, Readonly', - level: 'advanced', - content: - '`Record` cria um tipo objeto com chaves K e valores V. ' + - '`Partial` torna todas as propriedades opcionais. ' + - '`Readonly` torna todas as propriedades apenas leitura.', - task: 'Crie um tipo `UserRecord` usando Record.', - hint: 'type UserRecord = Record', + title: "Utility Types - Record, Partial, Readonly", + level: "advanced", + content: + "`Record` cria um tipo objeto com chaves K e valores V. " + + "`Partial` torna todas as propriedades opcionais. " + + "`Readonly` torna todas as propriedades apenas leitura.", + task: "Crie um tipo `UserRecord` usando Record.", + hint: "type UserRecord = Record", starterCode: `interface User { id: number name: string @@ -885,13 +885,13 @@ console.log("Partial:", JSON.stringify(partial))`, }, { id: 32, - title: 'Utility Types - Extract e Exclude', - level: 'advanced', + title: "Utility Types - Extract e Exclude", + level: "advanced", content: - '`Extract` extrai de T os tipos que são atribuíveis a U. ' + - '`Exclude` remove de T os tipos que são atribuíveis a U.', - task: 'Use Extract para obter apenas strings de um union type.', - hint: 'type Strings = Extract', + "`Extract` extrai de T os tipos que são atribuíveis a U. " + + "`Exclude` remove de T os tipos que são atribuíveis a U.", + task: "Use Extract para obter apenas strings de um union type.", + hint: "type Strings = Extract", starterCode: `type T = string | number | boolean | null type Strings = Extract @@ -908,13 +908,13 @@ console.log("NotNull:", bool)`, }, { id: 33, - title: 'Utility Types - ReturnType e Parameters', - level: 'advanced', + title: "Utility Types - ReturnType e Parameters", + level: "advanced", content: - '`ReturnType` obtém o tipo de retorno de uma função. ' + - '`Parameters` obtém os tipos dos parâmetros como tupla.', - task: 'Obtenha o tipo de retorno e parâmetros de uma função.', - hint: 'type R = ReturnType', + "`ReturnType` obtém o tipo de retorno de uma função. " + + "`Parameters` obtém os tipos dos parâmetros como tupla.", + task: "Obtenha o tipo de retorno e parâmetros de uma função.", + hint: "type R = ReturnType", starterCode: `function createUser(name: string, age: number): { name: string; age: number; id: number } { return { name, age, id: Math.random() } } @@ -930,13 +930,13 @@ console.log("Args:", args)`, }, { id: 34, - title: 'Type Guards', - level: 'basic', + title: "Type Guards", + level: "basic", content: - 'Type guards são expressões que refinam o tipo de uma variável. ' + - 'Use `typeof`, `instanceof`, ou personalizados com `is` para filtrar tipos em unions.', - task: 'Crie um type guard para verificar se um valor é string.', - hint: 'function isString(value: unknown): value is string { }', + "Type guards são expressões que refinam o tipo de uma variável. " + + "Use `typeof`, `instanceof`, ou personalizados com `is` para filtrar tipos em unions.", + task: "Crie um type guard para verificar se um valor é string.", + hint: "function isString(value: unknown): value is string { }", starterCode: `function isString(value: unknown): value is string { return typeof value === "string" } @@ -970,13 +970,13 @@ if (isDog(pet)) { }, { id: 35, - title: 'unknown e any', - level: 'basic', + title: "unknown e any", + level: "basic", content: - '`any` desabilita a verificação de tipos completamente. ' + + "`any` desabilita a verificação de tipos completamente. " + '`unknown` é o tipo "seguro" que representa qualquer valor — você deve refiná-lo antes de usar.', - task: 'Refine um tipo `unknown` para usá-lo com segurança.', - hint: 'Use type guards para verificar o tipo.', + task: "Refine um tipo `unknown` para usá-lo com segurança.", + hint: "Use type guards para verificar o tipo.", starterCode: `let anyValue: any = "hello" let unknownValue: unknown = "world" @@ -993,13 +993,13 @@ console.log(str)`, }, { id: 36, - title: 'never', - level: 'basic', + title: "never", + level: "basic", content: - '`never` representa valores que nunca ocorrem. Funções que sempre lançam erros ' + - 'ou loops infinitos têm tipo de retorno `never`. Também é usado em unions exaustivas.', - task: 'Crie uma função que lança erro e tem retorno never.', - hint: 'function error(): never { throw new Error(); }', + "`never` representa valores que nunca ocorrem. Funções que sempre lançam erros " + + "ou loops infinitos têm tipo de retorno `never`. Também é usado em unions exaustivas.", + task: "Crie uma função que lança erro e tem retorno never.", + hint: "function error(): never { throw new Error(); }", starterCode: `function throwError(message: string): never { throw new Error(message) } @@ -1030,11 +1030,11 @@ console.log(getDirection("North"))`, }, { id: 37, - title: 'keyof e Index Access Types', - level: 'advanced', + title: "keyof e Index Access Types", + level: "advanced", content: - '`keyof` obtém as chaves de um tipo como union. ' + - 'Use `T[K]` para acessar o tipo de uma propriedade específica.', + "`keyof` obtém as chaves de um tipo como union. " + + "Use `T[K]` para acessar o tipo de uma propriedade específica.", task: "Obtenha as chaves de User e o tipo da propriedade 'name'.", hint: 'type Keys = keyof User; type NameType = User["name"]', starterCode: `interface User { @@ -1059,13 +1059,13 @@ console.log(getProperty(user, "email"))`, }, { id: 38, - title: 'Generic Constraints', - level: 'basic', + title: "Generic Constraints", + level: "basic", content: - 'Constraints (restrições) usam `extends` para limitar os tipos que podem ser usados com generics. ' + - 'Isso garante que o tipo tenha as propriedades necessárias.', - task: 'Crie um generic que só aceita objetos com propriedade `length`.', - hint: 'function fn(arg: T)', + "Constraints (restrições) usam `extends` para limitar os tipos que podem ser usados com generics. " + + "Isso garante que o tipo tenha as propriedades necessárias.", + task: "Crie um generic que só aceita objetos com propriedade `length`.", + hint: "function fn(arg: T)", starterCode: `function getLength(arg: T): number { return arg.length } @@ -1083,13 +1083,13 @@ console.log("Merged:", JSON.stringify(result))`, }, { id: 39, - title: 'Generic Classes', - level: 'basic', + title: "Generic Classes", + level: "basic", content: - 'Classes genéricas permitem criar componentes reutilizáveis que funcionam com diferentes tipos. ' + - 'O tipo é especificado ao criar uma instância da classe.', - task: 'Crie uma classe `Box` que armazena um valor.', - hint: 'class Box { private content: T; }', + "Classes genéricas permitem criar componentes reutilizáveis que funcionam com diferentes tipos. " + + "O tipo é especificado ao criar uma instância da classe.", + task: "Crie uma classe `Box` que armazena um valor.", + hint: "class Box { private content: T; }", starterCode: `class Box { private content: T @@ -1117,13 +1117,13 @@ console.log("Updated:", numberBox.get())`, }, { id: 40, - title: 'Generic Interfaces', - level: 'basic', + title: "Generic Interfaces", + level: "basic", content: - 'Interfaces genéricas definem contratos que funcionam com múltiplos tipos. ' + - 'São a base de bibliotecas como React, Zod e Prisma.', - task: 'Crie uma interface `Repository` com métodos CRUD.', - hint: 'interface Repository { findAll(): T[]; }', + "Interfaces genéricas definem contratos que funcionam com múltiplos tipos. " + + "São a base de bibliotecas como React, Zod e Prisma.", + task: "Crie uma interface `Repository` com métodos CRUD.", + hint: "interface Repository { findAll(): T[]; }", starterCode: `interface Entity { id: number } @@ -1178,13 +1178,13 @@ console.log("Find 1:", repo.findById(1))`, }, { id: 41, - title: 'Tipagem de Error Handling', - level: 'basic', + title: "Tipagem de Error Handling", + level: "basic", content: - 'TypeScript melhora o tratamento de erros com melhor inferência em blocos try/catch. ' + - 'Especifique o tipo do erro para melhor autocomplete.', - task: 'Crie uma função que pode lançar erros e trate-os.', - hint: 'try { } catch (error) { if (error instanceof Error) { } }', + "TypeScript melhora o tratamento de erros com melhor inferência em blocos try/catch. " + + "Especifique o tipo do erro para melhor autocomplete.", + task: "Crie uma função que pode lançar erros e trate-os.", + hint: "try { } catch (error) { if (error instanceof Error) { } }", starterCode: `function divide(a: number, b: number): number { if (b === 0) { throw new Error("Division by zero is not allowed") @@ -1228,13 +1228,13 @@ try { }, { id: 42, - title: 'Async/Await e Promises', - level: 'basic', + title: "Async/Await e Promises", + level: "basic", content: - 'TypeScript suporta async/await completamente tipado. Funções async retornam Promises, ' + - 'e você pode tipar o valor resolvido.', - task: 'Crie uma função async que retorna um usuário tipado.', - hint: 'async function fetchUser(): Promise { }', + "TypeScript suporta async/await completamente tipado. Funções async retornam Promises, " + + "e você pode tipar o valor resolvido.", + task: "Crie uma função async que retorna um usuário tipado.", + hint: "async function fetchUser(): Promise { }", starterCode: `interface User { id: number name: string @@ -1270,13 +1270,13 @@ main()`, }, { id: 43, - title: 'this em Tipos', - level: 'basic', + title: "this em Tipos", + level: "basic", content: - 'TypeScript permite tipar `this` em métodos. Use `this` como primeiro parâmetro ' + - 'para garantir que métodos sejam chamados no contexto correto (fluent API).', - task: 'Crie uma fluent API com métodos que retornam `this`.', - hint: 'add(name: string): this { }', + "TypeScript permite tipar `this` em métodos. Use `this` como primeiro parâmetro " + + "para garantir que métodos sejam chamados no contexto correto (fluent API).", + task: "Crie uma fluent API com métodos que retornam `this`.", + hint: "add(name: string): this { }", starterCode: `class Builder { private parts: string[] = [] @@ -1329,13 +1329,13 @@ console.log("Calc result:", calc.result())`, }, { id: 44, - title: 'Optional Chaining e Nullish Coalescing', - level: 'basic', + title: "Optional Chaining e Nullish Coalescing", + level: "basic", content: - '`?.` acessa propriedades profundas sem erro se algo for null/undefined. ' + - '`??` retorna o operando direito se o esquerdo for null/undefined.', - task: 'Use optional chaining para acessar propriedade aninhada.', - hint: 'user?.address?.city', + "`?.` acessa propriedades profundas sem erro se algo for null/undefined. " + + "`??` retorna o operando direito se o esquerdo for null/undefined.", + task: "Use optional chaining para acessar propriedade aninhada.", + hint: "user?.address?.city", starterCode: `interface User { name: string address?: { @@ -1368,13 +1368,13 @@ console.log("Zero:", zero)`, }, { id: 45, - title: 'Non-null Assertion Operator', - level: 'basic', + title: "Non-null Assertion Operator", + level: "basic", content: - '`!` diz ao TypeScript que um valor não é null/undefined. Use com cautela — ' + - 'só quando você tem certeza que o valor existe.', - task: 'Use non-null assertion para acessar propriedade garantida.', - hint: 'element!.value', + "`!` diz ao TypeScript que um valor não é null/undefined. Use com cautela — " + + "só quando você tem certeza que o valor existe.", + task: "Use non-null assertion para acessar propriedade garantida.", + hint: "element!.value", starterCode: `function getElement(): HTMLInputElement | null { return document.createElement("input") } @@ -1392,13 +1392,13 @@ console.log("Result:", result)`, }, { id: 46, - title: 'Type Casting vs Assertion', - level: 'basic', + title: "Type Casting vs Assertion", + level: "basic", content: - 'Type assertions (`as`) convertem tipos. Use-as quando você sabe mais sobre o tipo ' + - 'do que o TypeScript. Diferente de casting em outras linguagens, não converte o valor.', - task: 'Use assertion para converter um tipo para outro.', - hint: 'const num = value as number', + "Type assertions (`as`) convertem tipos. Use-as quando você sabe mais sobre o tipo " + + "do que o TypeScript. Diferente de casting em outras linguagens, não converte o valor.", + task: "Use assertion para converter um tipo para outro.", + hint: "const num = value as number", starterCode: `let input: unknown = "123" const strLength1 = (input as string).length @@ -1430,13 +1430,13 @@ processAnimal(dog)`, }, { id: 47, - title: 'Template Literal Types', - level: 'advanced', + title: "Template Literal Types", + level: "advanced", content: - 'Template literal types criam novos tipos usando strings templates. ' + - 'Combine com infer para extrair e manipular strings em tipos.', - task: 'Crie um tipo que cria getters automaticamente.', - hint: 'type Getters = { [K in keyof T as `get${K}`]: () => T[K] }', + "Template literal types criam novos tipos usando strings templates. " + + "Combine com infer para extrair e manipular strings em tipos.", + task: "Crie um tipo que cria getters automaticamente.", + hint: "type Getters = { [K in keyof T as `get${K}`]: () => T[K] }", starterCode: `type World = "world" type Greeting = \`hello \${World}\` @@ -1465,12 +1465,12 @@ console.log(getters.getAge())`, }, { id: 48, - title: 'Discriminated Unions', - level: 'basic', + title: "Discriminated Unions", + level: "basic", content: - 'Crie unions com uma propriedade em comum (discriminador) para facilitar o TypeScript ' + - 'identificar qual membro da union está em uso. Muito útil para state management.', - task: 'Crie uma discriminated union para formatos de arquivo.', + "Crie unions com uma propriedade em comum (discriminador) para facilitar o TypeScript " + + "identificar qual membro da union está em uso. Muito útil para state management.", + task: "Crie uma discriminated union para formatos de arquivo.", hint: 'type File = { type: "image", data: ... } | { type: "video", data: ... }', starterCode: `type Loading = { status: "loading" } type Success = { status: "success"; data: string } @@ -1502,13 +1502,13 @@ handleResult(errorResult)`, }, { id: 49, - title: 'Mixin Classes', - level: 'advanced', + title: "Mixin Classes", + level: "advanced", content: - 'Mixins são funções que recebem uma classe e retornam uma nova classe com funcionalidades extras. ' + - 'Útil para composição quando herança simples não é suficiente.', - task: 'Crie um mixin `Serializable` que adiciona método toJSON.', - hint: 'function Serializable>(Base: T)', + "Mixins são funções que recebem uma classe e retornam uma nova classe com funcionalidades extras. " + + "Útil para composição quando herança simples não é suficiente.", + task: "Crie um mixin `Serializable` que adiciona método toJSON.", + hint: "function Serializable>(Base: T)", starterCode: `type Constructor = new (...args: any[]) => T function Serializable>(Base: T) { @@ -1541,13 +1541,13 @@ console.log("User:", JSON.stringify(user, null, 2))`, }, { id: 50, - title: 'Declaration Merging', - level: 'advanced', + title: "Declaration Merging", + level: "advanced", content: 'TypeScript permite que interfaces e namespaces com o mesmo nome sejam "mesclados". ' + - 'Interfaces são mescladas automaticamente, namespaces requerem `export`.', - task: 'Crie uma interface que é mesclada com outra.', - hint: 'interface Animal { name: string; } interface Animal { age: number; }', + "Interfaces são mescladas automaticamente, namespaces requerem `export`.", + task: "Crie uma interface que é mesclada com outra.", + hint: "interface Animal { name: string; } interface Animal { age: number; }", starterCode: `interface User { name: string } @@ -1582,13 +1582,13 @@ console.log("Declaration merging works!")`, }, { id: 51, - title: 'Type-safe Event Emitter', - level: 'advanced', + title: "Type-safe Event Emitter", + level: "advanced", content: - 'Crie um emissor de eventos type-safe que garante que listeners e eventos correspondam. ' + - 'Use generics para mapear nomes de eventos para seus payloads.', - task: 'Crie um tipo EventMap e implemente um emitter.', - hint: 'type Events = { event: payload }', + "Crie um emissor de eventos type-safe que garante que listeners e eventos correspondam. " + + "Use generics para mapear nomes de eventos para seus payloads.", + task: "Crie um tipo EventMap e implemente um emitter.", + hint: "type Events = { event: payload }", starterCode: `type EventMap = { userJoined: { userId: number; name: string } userLeft: { userId: number } @@ -1630,13 +1630,13 @@ emitter.emit("message", { from: "Bob", text: "Hello!" })`, }, { id: 52, - title: 'Builder Pattern com Generics', - level: 'advanced', + title: "Builder Pattern com Generics", + level: "advanced", content: - 'O padrão Builder permite construir objetos complexos passo a passo. ' + - 'Com generics, podemos garantir que os métodos retornem o builder correto.', - task: 'Implemente um builder para criar usuários com validation.', - hint: 'Use this возврате para method chaining.', + "O padrão Builder permite construir objetos complexos passo a passo. " + + "Com generics, podemos garantir que os métodos retornem o builder correto.", + task: "Implemente um builder para criar usuários com validation.", + hint: "Use this возврате para method chaining.", starterCode: `class UserBuilder { private user: { name?: string; age?: number; email?: string } = {} @@ -1676,13 +1676,13 @@ console.log("Built user:", JSON.stringify(user))`, }, { id: 53, - title: 'Currying e Function Composition', - level: 'basic', + title: "Currying e Function Composition", + level: "basic", content: - 'Currying transforma funções multi-arg em sequências de funções single-arg. ' + - 'Composition combina funções para criar pipelines de dados.', - task: 'Crie funções curried e as compõe.', - hint: 'const add = (a: number) => (b: number) => a + b', + "Currying transforma funções multi-arg em sequências de funções single-arg. " + + "Composition combina funções para criar pipelines de dados.", + task: "Crie funções curried e as compõe.", + hint: "const add = (a: number) => (b: number) => a + b", starterCode: `const add = (a: number) => (b: number): number => a + b const multiply = (a: number) => (b: number): number => a * b const subtract = (a: number) => (b: number): number => a - b @@ -1708,13 +1708,13 @@ console.log("pipe(add10, double, subtract5)(5):", processNumber(5))`, }, { id: 54, - title: 'Type-safe API Client', - level: 'advanced', + title: "Type-safe API Client", + level: "advanced", content: - 'Crie um cliente HTTP que infere tipos de resposta automaticamente. ' + - 'Use generics para tipar endpoints e responses.', - task: 'Crie um cliente com tipos para GET e POST.', - hint: 'class ApiClient { get(url): Promise }', + "Crie um cliente HTTP que infere tipos de resposta automaticamente. " + + "Use generics para tipar endpoints e responses.", + task: "Crie um cliente com tipos para GET e POST.", + hint: "class ApiClient { get(url): Promise }", starterCode: `interface User { id: number name: string @@ -1761,13 +1761,13 @@ createUser({ name: "Alice", email: "alice@example.com" }) }, { id: 55, - title: 'Flattened Union Types', - level: 'advanced', + title: "Flattened Union Types", + level: "advanced", content: - 'Crie tipos union complexos e use distribuição para transformá-los. ' + - 'Útil para criar unions de strings literais automaticamente.', - task: 'Crie uma union de métodos HTTP a partir de um array.', - hint: 'type Method = typeof methods[number]', + "Crie tipos union complexos e use distribuição para transformá-los. " + + "Útil para criar unions de strings literais automaticamente.", + task: "Crie uma union de métodos HTTP a partir de um array.", + hint: "type Method = typeof methods[number]", starterCode: `const methods = ["get", "post", "put", "delete", "patch"] as const type HttpMethod = typeof methods[number] @@ -1808,13 +1808,13 @@ console.log("Variants:", variants)`, }, { id: 56, - title: 'Immutable Update Patterns', - level: 'basic', + title: "Immutable Update Patterns", + level: "basic", content: - 'Atualize objetos e arrays de forma imutável para evitar mutações acidentais. ' + - 'Use spread operator e métodos que retornam novos arrays.', - task: 'Atualize um objeto aninhado de forma imutável.', - hint: 'Use spread para criar novas referências.', + "Atualize objetos e arrays de forma imutável para evitar mutações acidentais. " + + "Use spread operator e métodos que retornam novos arrays.", + task: "Atualize um objeto aninhado de forma imutável.", + hint: "Use spread para criar novas referências.", starterCode: `interface State { user: { profile: { @@ -1864,13 +1864,13 @@ console.log("Same reference?", state === newState)`, }, { id: 57, - title: 'Recursive Types', - level: 'advanced', + title: "Recursive Types", + level: "advanced", content: - 'Types recursivos permitem representar estruturas hierárquicas como árvores e listas. ' + - 'Útil para JSON, ASTs, e estruturas de dados aninhadas.', - task: 'Crie um tipo para uma árvore de diretórios.', - hint: 'interface TreeNode { name: string; children?: TreeNode[] }', + "Types recursivos permitem representar estruturas hierárquicas como árvores e listas. " + + "Útil para JSON, ASTs, e estruturas de dados aninhadas.", + task: "Crie um tipo para uma árvore de diretórios.", + hint: "interface TreeNode { name: string; children?: TreeNode[] }", starterCode: `interface TreeNode { name: string type: "file" | "folder" @@ -1920,12 +1920,12 @@ console.log("JSON:", JSON.stringify(json, null, 2))`, }, { id: 58, - title: 'Branded Types', - level: 'advanced', + title: "Branded Types", + level: "advanced", content: 'Branded types adicionam "tags" a tipos existentes para区分 tipos primitivos. ' + - 'Útil para IDs, currencies, e valores que precisam de validação semântica.', - task: 'Crie branded types para UserId e OrderId.', + "Útil para IDs, currencies, e valores que precisam de validação semântica.", + task: "Crie branded types para UserId e OrderId.", hint: 'type UserId = string & { __brand: "UserId" }', starterCode: `type UserId = string & { readonly __brand: "UserId" } type OrderId = string & { readonly __brand: "OrderId" } @@ -1963,12 +1963,12 @@ console.log("Email:", email)`, }, { id: 59, - title: 'Finite State Machines', - level: 'advanced', + title: "Finite State Machines", + level: "advanced", content: - 'State machines definem um número finito de estados e transições entre eles. ' + - 'TypeScript pode garantir que apenas transições válidas ocorram.', - task: 'Crie um state machine para um pedido.', + "State machines definem um número finito de estados e transições entre eles. " + + "TypeScript pode garantir que apenas transições válidas ocorram.", + task: "Crie um state machine para um pedido.", hint: 'type State = "pending" | "shipped" | "delivered"', starterCode: `type OrderState = "pending" | "confirmed" | "shipped" | "delivered" | "cancelled" @@ -2023,12 +2023,12 @@ console.log("After deliver:", order.state)`, }, { id: 60, - title: 'Weak Types e Type Gards', - level: 'advanced', + title: "Weak Types e Type Gards", + level: "advanced", content: - 'Weak types são tipos com todas propriedades opcionais. ' + - 'TypeScript tem verificação especial para garantir que pelo menos uma propriedade seja fornecida.', - task: 'Crie uma função que aceita apenas opções válidas.', + "Weak types são tipos com todas propriedades opcionais. " + + "TypeScript tem verificação especial para garantir que pelo menos uma propriedade seja fornecida.", + task: "Crie uma função que aceita apenas opções válidas.", hint: 'Use "at least one" constraint com keyof', starterCode: `type Options = { timeout?: number @@ -2068,13 +2068,13 @@ console.log(processPoint({ name: "A", x: 10, y: 20 }))`, }, { id: 61, - title: 'Proxy e Interceptação', - level: 'advanced', + title: "Proxy e Interceptação", + level: "advanced", content: - 'Proxy permite interceptar operações como leitura, escrita, e invocação de métodos. ' + - 'Útil para logging, validation, e lazy loading.', - task: 'Crie um proxy para validar propriedades.', - hint: 'new Proxy(target, { get, set })', + "Proxy permite interceptar operações como leitura, escrita, e invocação de métodos. " + + "Útil para logging, validation, e lazy loading.", + task: "Crie um proxy para validar propriedades.", + hint: "new Proxy(target, { get, set })", starterCode: `interface User { name: string age: number @@ -2114,12 +2114,12 @@ try { }, { id: 62, - title: 'Symbol e Metadata', - level: 'basic', + title: "Symbol e Metadata", + level: "basic", content: - 'Symbols são valores únicos que podem servir como chaves de propriedades. ' + + "Symbols são valores únicos que podem servir como chaves de propriedades. " + 'Úteis para criar propriedades "escondidas" e para reflection.', - task: 'Use Symbol para criar uma propriedade privada.', + task: "Use Symbol para criar uma propriedade privada.", hint: 'const privateKey = Symbol("private")', starterCode: `const nameKey = Symbol("name") const ageKey = Symbol("age") @@ -2156,13 +2156,13 @@ console.log("Cached:", cache.get(key1))`, }, { id: 63, - title: 'Asserts Type Guards', - level: 'advanced', + title: "Asserts Type Guards", + level: "advanced", content: - 'Asserts type guards são funções que verificam e refinam tipos, ' + - 'lançando erro se a condição não for atendida.', - task: 'Crie um assert que verifica se um valor é número positivo.', - hint: 'function assert(condition, message)', + "Asserts type guards são funções que verificam e refinam tipos, " + + "lançando erro se a condição não for atendida.", + task: "Crie um assert que verifica se um valor é número positivo.", + hint: "function assert(condition, message)", starterCode: `function assert(condition: boolean, message: string): asserts condition { if (!condition) { throw new Error(message) @@ -2196,13 +2196,13 @@ console.log("Data length:", data.length)`, }, { id: 64, - title: 'Infer com Conditional Types', - level: 'advanced', + title: "Infer com Conditional Types", + level: "advanced", content: - '`infer` extrai tipos de dentro de outros tipos. ' + - 'Pode extrair tipos de funções, arrays, promises, e objetos.', - task: 'Extraia o tipo de elemento de um array.', - hint: 'type ArrayElement = T extends (infer U)[] ? U : never', + "`infer` extrai tipos de dentro de outros tipos. " + + "Pode extrair tipos de funções, arrays, promises, e objetos.", + task: "Extraia o tipo de elemento de um array.", + hint: "type ArrayElement = T extends (infer U)[] ? U : never", starterCode: `type ReturnTypeOf = T extends (...args: any[]) => infer R ? R : never type ParametersOf = T extends (...args: infer P) => any ? P : never type ArrayElement = T extends (infer U)[] ? U : never @@ -2235,13 +2235,13 @@ console.log("Promise:", pv)`, }, { id: 65, - title: 'Type-safe Event Bus', - level: 'advanced', + title: "Type-safe Event Bus", + level: "advanced", content: - 'Crie um event bus que garante type safety para eventos e handlers. ' + - 'Use mapped types para derivar tipos de eventos.', - task: 'Implemente um event bus com subscribe e emit type-safe.', - hint: 'Use keyof e generics para inferência.', + "Crie um event bus que garante type safety para eventos e handlers. " + + "Use mapped types para derivar tipos de eventos.", + task: "Implemente um event bus com subscribe e emit type-safe.", + hint: "Use keyof e generics para inferência.", starterCode: `type Events = { login: { userId: number; timestamp: Date } logout: { userId: number } @@ -2296,13 +2296,13 @@ bus.emit("purchase", { userId: 1, amount: 99.99 })`, }, { id: 66, - title: 'Readonly Deep', - level: 'advanced', + title: "Readonly Deep", + level: "advanced", content: - 'Crie um tipo que torna todas as propriedades aninhadas readonly recursivamente. ' + - 'Útil para garantir imutabilidade em objetos complexos.', - task: 'Crie um tipo DeepReadonly.', - hint: 'type DeepReadonly = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K] }', + "Crie um tipo que torna todas as propriedades aninhadas readonly recursivamente. " + + "Útil para garantir imutabilidade em objetos complexos.", + task: "Crie um tipo DeepReadonly.", + hint: "type DeepReadonly = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K] }", starterCode: `type DeepReadonly = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly : T[K] } @@ -2338,13 +2338,13 @@ company.employees.push({ name: "New", role: "Manager" })`, }, { id: 67, - title: 'Strict Null Checks em filters', - level: 'basic', + title: "Strict Null Checks em filters", + level: "basic", content: - 'Filtrar arrays pode criar tipos union com undefined. ' + - 'Aprenda a usar type guards para refiná-los corretamente.', - task: 'Filtre valores nulos e refine o tipo.', - hint: 'arr.filter((x): x is Type => x !== null)', + "Filtrar arrays pode criar tipos union com undefined. " + + "Aprenda a usar type guards para refiná-los corretamente.", + task: "Filtre valores nulos e refine o tipo.", + hint: "arr.filter((x): x is Type => x !== null)", starterCode: `interface User { id: number name: string @@ -2380,12 +2380,12 @@ if (result) { }, { id: 68, - title: 'Enum vs Union vs Const Object', - level: 'basic', + title: "Enum vs Union vs Const Object", + level: "basic", content: - 'Compare enums, union types, e objetos const para entender quando usar cada um. ' + - 'Cada abordagem tem prós e contras em termos de runtime e type safety.', - task: 'Converta um enum para union type e compare.', + "Compare enums, union types, e objetos const para entender quando usar cada um. " + + "Cada abordagem tem prós e contras em termos de runtime e type safety.", + task: "Converta um enum para union type e compare.", hint: 'type Direction = "N" | "S" | "E" | "W"', starterCode: `enum DirectionEnum { North = "N", @@ -2420,13 +2420,13 @@ console.log("All approaches work!")`, }, { id: 69, - title: 'Type-safe CSV Parser', - level: 'advanced', + title: "Type-safe CSV Parser", + level: "advanced", content: - 'Crie um parser de CSV que infere tipos de colunas. ' + - 'Use generics para mapear headers para tipos.', - task: 'Parse CSV e infira tipos das colunas.', - hint: 'function parseCSV(csv: string): T[]', + "Crie um parser de CSV que infere tipos de colunas. " + + "Use generics para mapear headers para tipos.", + task: "Parse CSV e infira tipos das colunas.", + hint: "function parseCSV(csv: string): T[]", starterCode: `interface User { id: number name: string @@ -2470,13 +2470,13 @@ console.log("First user:", first)`, }, { id: 70, - title: 'Schema Validation com Mapped Types', - level: 'advanced', + title: "Schema Validation com Mapped Types", + level: "advanced", content: - 'Crie um schema validator que verifica objetos contra definições de tipos. ' + - 'Use mapped types para transformar o schema em validadores.', - task: 'Valide um objeto contra um schema.', - hint: 'Use Record para mapear campos para validadores.', + "Crie um schema validator que verifica objetos contra definições de tipos. " + + "Use mapped types para transformar o schema em validadores.", + task: "Valide um objeto contra um schema.", + hint: "Use Record para mapear campos para validadores.", starterCode: `type Validator = (value: unknown) => T type Schema = { @@ -2530,13 +2530,13 @@ console.log("Validated:", validated)`, }, { id: 71, - title: 'Polymorphic this Types', - level: 'advanced', + title: "Polymorphic this Types", + level: "advanced", content: - 'Use `this` como tipo de retorno para criar fluent APIs onde métodos retornam ' + - 'a classe concreta, não a classe base. Útil para herança.', - task: 'Crie uma fluent API com this polimórfico.', - hint: 'class Builder { add(): this { } }', + "Use `this` como tipo de retorno para criar fluent APIs onde métodos retornam " + + "a classe concreta, não a classe base. Útil para herança.", + task: "Crie uma fluent API com this polimórfico.", + hint: "class Builder { add(): this { } }", starterCode: `class Builder { protected parts: string[] = [] @@ -2599,13 +2599,13 @@ console.log("Result:", calc.result())`, }, { id: 72, - title: 'Tuple Types em Funções', - level: 'basic', + title: "Tuple Types em Funções", + level: "basic", content: - 'Tuplas podem ser usadas para tipar parâmetros de funções com múltiplos valores. ' + - 'Útil para funções que retornam múltiplos valores.', - task: 'Crie uma função que retorna nome e idade como tupla.', - hint: 'function getPerson(): [string, number] { }', + "Tuplas podem ser usadas para tipar parâmetros de funções com múltiplos valores. " + + "Útil para funções que retornam múltiplos valores.", + task: "Crie uma função que retorna nome e idade como tupla.", + hint: "function getPerson(): [string, number] { }", starterCode: `function getUser(): [string, number, boolean] { return ["Alice", 25, true] } @@ -2642,13 +2642,13 @@ console.log("Parsed:", date)`, }, { id: 73, - title: 'Interface vs Type Alias', - level: 'basic', + title: "Interface vs Type Alias", + level: "basic", content: - 'Interfaces são melhores para objetos e classes, permitindo extends e merge. ' + - 'Type aliases são melhores para unions, intersections, e tipos primitivos.', - task: 'Compare interface e type para o mesmo objeto.', - hint: 'interface para objetos, type para unions', + "Interfaces são melhores para objetos e classes, permitindo extends e merge. " + + "Type aliases são melhores para unions, intersections, e tipos primitivos.", + task: "Compare interface e type para o mesmo objeto.", + hint: "interface para objetos, type para unions", starterCode: `interface UserI { name: string age: number @@ -2685,12 +2685,12 @@ console.log("Pair:", pair)`, }, { id: 74, - title: 'Module Resolution', - level: 'advanced', + title: "Module Resolution", + level: "advanced", content: - 'TypeScript resolve módulos de diferentes formas: classic, node, node16, nodenext. ' + - 'Entenda as diferenças para configurar projetos corretamente.', - task: 'Configure paths e baseUrl para imports.', + "TypeScript resolve módulos de diferentes formas: classic, node, node16, nodenext. " + + "Entenda as diferenças para configurar projetos corretamente.", + task: "Configure paths e baseUrl para imports.", hint: 'Configure "baseUrl" e "paths" no tsconfig.json', starterCode: `// Simulando paths do tsconfig // { @@ -2726,12 +2726,12 @@ console.log("Resolved @/components:", resolvePath("@/components"))`, }, { id: 75, - title: 'Ambient Modules e Triple-Slash', - level: 'advanced', + title: "Ambient Modules e Triple-Slash", + level: "advanced", content: - 'Use triple-slash directives para declarar dependências de módulos. ' + - 'Útil para incluir tipos e módulos em arquivos compilados.', - task: 'Use triple-slash para declarar um módulo.', + "Use triple-slash directives para declarar dependências de módulos. " + + "Útil para incluir tipos e módulos em arquivos compilados.", + task: "Use triple-slash para declarar um módulo.", hint: '/// ', starterCode: `/// @@ -2754,13 +2754,13 @@ console.log("Ambient declarations loaded!")`, }, { id: 76, - title: 'Union Narrowing com never', - level: 'advanced', + title: "Union Narrowing com never", + level: "advanced", content: - 'Use `never` em unions para forçar o TypeScript a verificar todos os casos. ' + - 'Útil em switch statements exaustivos.', - task: 'Crie um switch exaustivo.', - hint: 'default: const _: never = value', + "Use `never` em unions para forçar o TypeScript a verificar todos os casos. " + + "Útil em switch statements exaustivos.", + task: "Crie um switch exaustivo.", + hint: "default: const _: never = value", starterCode: `type Shape = | { kind: "circle"; radius: number } | { kind: "square"; side: number } @@ -2790,13 +2790,13 @@ shapes.forEach(s => console.log(\`Area: \${area(s).toFixed(2)}\`))`, }, { id: 77, - title: 'Type-safe Event Listeners', - level: 'advanced', + title: "Type-safe Event Listeners", + level: "advanced", content: - 'Crie funções que adicionam event listeners com type safety total. ' + - 'O handler deve ter o tipo correto baseado no evento.', - task: 'Crie uma função addEventListener type-safe.', - hint: 'Use generics para inferir o handler type.', + "Crie funções que adicionam event listeners com type safety total. " + + "O handler deve ter o tipo correto baseado no evento.", + task: "Crie uma função addEventListener type-safe.", + hint: "Use generics para inferir o handler type.", starterCode: `type EventMap = { click: { x: number; y: number } keydown: { key: string } @@ -2833,13 +2833,13 @@ on("focus", () => console.log("focused"))`, }, { id: 78, - title: 'Intersection Types com Mixins', - level: 'advanced', + title: "Intersection Types com Mixins", + level: "advanced", content: - 'Intersection types combinam múltiplos tipos em um. ' + - 'Útil para adicionar funcionalidades via mixins ou criar tipos compuestos.', - task: 'Crie um tipo que é both Serializable e Validatable.', - hint: 'type T = Serializable & Validatable', + "Intersection types combinam múltiplos tipos em um. " + + "Útil para adicionar funcionalidades via mixins ou criar tipos compuestos.", + task: "Crie um tipo que é both Serializable e Validatable.", + hint: "type T = Serializable & Validatable", starterCode: `interface Serializable { toJSON(): Record } @@ -2894,13 +2894,13 @@ io.write("hello")`, }, { id: 79, - title: 'Type-safe Console Methods', - level: 'basic', + title: "Type-safe Console Methods", + level: "basic", content: - 'TypeScript não verifica console por padrão. ' + - 'Crie wrappers type-safe para logging consistente.', - task: 'Crie funções de log type-safe.', - hint: 'function log(message: T): void', + "TypeScript não verifica console por padrão. " + + "Crie wrappers type-safe para logging consistente.", + task: "Crie funções de log type-safe.", + hint: "function log(message: T): void", starterCode: `function log(message: T): void { console.log(\`[LOG] \${message}\`) } @@ -2930,13 +2930,13 @@ console.log("Result:", result)`, }, { id: 80, - title: 'Pattern Matching Simples', - level: 'basic', + title: "Pattern Matching Simples", + level: "basic", content: - 'Implemente um pattern matching simples com generics. ' + - 'Similar ao match em linguagens funcionais.', - task: 'Crie uma função match que execute patterns.', - hint: 'function match(value: T, patterns: Record): R', + "Implemente um pattern matching simples com generics. " + + "Similar ao match em linguagens funcionais.", + task: "Crie uma função match que execute patterns.", + hint: "function match(value: T, patterns: Record): R", starterCode: `function match(value: T, patterns: Record): R { if (value in patterns) { return patterns[value] @@ -2981,13 +2981,13 @@ console.log(reduce({ type: "reset" }))`, }, { id: 81, - title: 'Variadic Tuple Types', - level: 'advanced', + title: "Variadic Tuple Types", + level: "advanced", content: - 'Variadic tuples permitem criar tipos que aceitam número variável de elementos. ' + - 'Útil para concatenação de tipos e tail recursion.', - task: 'Crie um tipo que concatena tuplas.', - hint: 'type Concat = [...T, ...U]', + "Variadic tuples permitem criar tipos que aceitam número variável de elementos. " + + "Útil para concatenação de tipos e tail recursion.", + task: "Crie um tipo que concatena tuplas.", + hint: "type Concat = [...T, ...U]", starterCode: `type Concat = [...T, ...U] type A = Concat<[1, 2], [3, 4]> @@ -3013,13 +3013,13 @@ const d: D = [2, 3]`, }, { id: 82, - title: 'Awaited Type para Promises', - level: 'advanced', + title: "Awaited Type para Promises", + level: "advanced", content: - 'O utility type `Awaited` extrai o tipo resolvido de uma Promise. ' + - 'Funciona recursivamente para Promises aninhadas.', - task: 'Use Awaited para tipar o resultado de async functions.', - hint: 'type Result = Awaited>', + "O utility type `Awaited` extrai o tipo resolvido de uma Promise. " + + "Funciona recursivamente para Promises aninhadas.", + task: "Use Awaited para tipar o resultado de async functions.", + hint: "type Result = Awaited>", starterCode: `type Awaited = T extends Promise ? Awaited : T async function fetchUser(): Promise<{ id: number; name: string }> { @@ -3048,11 +3048,11 @@ getData()`, }, { id: 83, - title: 'Brand Keys em Mapped Types', - level: 'advanced', + title: "Brand Keys em Mapped Types", + level: "advanced", content: - 'Use template literal types em mapped types para criar transformações de chaves. ' + - 'Útil para adicionar prefixos/sufixos ou converter convenções.', + "Use template literal types em mapped types para criar transformações de chaves. " + + "Útil para adicionar prefixos/sufixos ou converter convenções.", task: "Crie um mapped type que adiciona prefixo 'get' a métodos.", hint: "type WithGetters = { [K in keyof T as 'get' + K]: () => T[K] }", starterCode: `type WithGetters = { @@ -3092,13 +3092,13 @@ setters.setName("Bob")`, }, { id: 84, - title: 'Type-safe React-like setState', - level: 'advanced', + title: "Type-safe React-like setState", + level: "advanced", content: - 'Implemente um hook de estado similar ao useState do React. ' + - 'O setter deve permitir update parcial e inferir tipos corretamente.', - task: 'Crie um useState simplificado com tipos inferidos.', - hint: 'function useState(initial: T): [() => T, (value: T | ((prev: T) => T)) => void]', + "Implemente um hook de estado similar ao useState do React. " + + "O setter deve permitir update parcial e inferir tipos corretamente.", + task: "Crie um useState simplificado com tipos inferidos.", + hint: "function useState(initial: T): [() => T, (value: T | ((prev: T) => T)) => void]", starterCode: `function useState(initial: T) { let state = initial @@ -3131,13 +3131,13 @@ console.log("Final count:", count())`, }, { id: 85, - title: 'Deep Partial Type', - level: 'advanced', + title: "Deep Partial Type", + level: "advanced", content: - 'Partial torna propriedades de primeiro nível opcionais. ' + - 'DeepPartial torna TODAS as propriedades aninhadas opcionais recursivamente.', - task: 'Crie um tipo DeepPartial.', - hint: 'type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] }', + "Partial torna propriedades de primeiro nível opcionais. " + + "DeepPartial torna TODAS as propriedades aninhadas opcionais recursivamente.", + task: "Crie um tipo DeepPartial.", + hint: "type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] }", starterCode: `type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] } @@ -3191,13 +3191,13 @@ function updateCompany(current: Company, updates: PartialCompany): Company { }, { id: 86, - title: 'Extract Keys por Tipo de Valor', - level: 'advanced', + title: "Extract Keys por Tipo de Valor", + level: "advanced", content: - 'Crie um tipo que extrai chaves de um objeto baseado no tipo de seus valores. ' + - 'Útil para encontrar campos de um certo tipo.', - task: 'Extraia chaves cujos valores são do tipo string.', - hint: 'type KeysOfType = { [K in keyof T]: T[K] extends U ? K : never }[keyof T]', + "Crie um tipo que extrai chaves de um objeto baseado no tipo de seus valores. " + + "Útil para encontrar campos de um certo tipo.", + task: "Extraia chaves cujos valores são do tipo string.", + hint: "type KeysOfType = { [K in keyof T]: T[K] extends U ? K : never }[keyof T]", starterCode: `type KeysOfType = { [K in keyof T]: T[K] extends U ? K : never }[keyof T] @@ -3240,12 +3240,12 @@ console.log("Numbers:", numbers)`, }, { id: 87, - title: 'Type-safe Redux-like Reducer', - level: 'advanced', + title: "Type-safe Redux-like Reducer", + level: "advanced", content: - 'Implemente um reducer type-safe similar ao Redux. ' + - 'O tipo de ação determina quais payloads são válidos.', - task: 'Crie um reducer com actions type-safe.', + "Implemente um reducer type-safe similar ao Redux. " + + "O tipo de ação determina quais payloads são válidos.", + task: "Crie um reducer com actions type-safe.", hint: 'type Action = { type: "TYPE"; payload: T }', starterCode: `type Action = | { type: "increment"; payload: number } @@ -3296,13 +3296,13 @@ console.log("After reset:", state.count)`, }, { id: 88, - title: 'Constructor Parameters Type', - level: 'advanced', + title: "Constructor Parameters Type", + level: "advanced", content: - '`ConstructorParameters` extrai os tipos de parâmetros do construtor de T. ' + - 'Útil para criar factories e injeção de dependência.', - task: 'Use ConstructorParameters para criar uma factory.', - hint: 'type CtorParams = ConstructorParameters', + "`ConstructorParameters` extrai os tipos de parâmetros do construtor de T. " + + "Útil para criar factories e injeção de dependência.", + task: "Use ConstructorParameters para criar uma factory.", + hint: "type CtorParams = ConstructorParameters", starterCode: `type ConstructorParameters any> = T extends new (...args: infer P) => any ? P : never @@ -3343,13 +3343,13 @@ console.log("Product:", product.name, product.price)`, }, { id: 89, - title: 'Optional Keys e Required Keys', - level: 'advanced', + title: "Optional Keys e Required Keys", + level: "advanced", content: - '`Required` torna todas as propriedades obrigatórias. ' + - '`Optional` (custom) pode fazer o oposto, ou criar tipos que têm apenas opcionais.', - task: 'Extraia chaves opcionais e obrigatórias separadamente.', - hint: 'type OptionalKeys = { [K in keyof T]: T extends { [K]: T[K] } ? never : K }[keyof T]', + "`Required` torna todas as propriedades obrigatórias. " + + "`Optional` (custom) pode fazer o oposto, ou criar tipos que têm apenas opcionais.", + task: "Extraia chaves opcionais e obrigatórias separadamente.", + hint: "type OptionalKeys = { [K in keyof T]: T extends { [K]: T[K] } ? never : K }[keyof T]", starterCode: `type OptionalKeys = { [K in keyof T]: {} extends Pick ? K : never }[keyof T] @@ -3387,13 +3387,13 @@ console.log("Validation:", result)`, }, { id: 90, - title: 'Type-safe Event Bus Final', - level: 'advanced', + title: "Type-safe Event Bus Final", + level: "advanced", content: - 'Combine tudo: generics, conditional types, e mapped types ' + - 'para criar um event bus completamente type-safe.', - task: 'Crie um event bus com inferred handlers.', - hint: 'Use infer para extrair tipos de eventos.', + "Combine tudo: generics, conditional types, e mapped types " + + "para criar um event bus completamente type-safe.", + task: "Crie um event bus com inferred handlers.", + hint: "Use infer para extrair tipos de eventos.", starterCode: `type EventMap = Record type EventReceiver = (params: T) => void @@ -3445,13 +3445,13 @@ bus.emit("purchase", { amount: 99.99, item: "E-book" })`, }, { id: 91, - title: 'Omit vs Exclude', - level: 'basic', + title: "Omit vs Exclude", + level: "basic", content: - '`Omit` remove propriedades de um tipo objeto. ' + - '`Exclude` remove tipos de uma union. Entenda a diferença.', - task: 'Use Omit para objeto e Exclude para union.', - hint: 'Omit para objetos, Exclude para unions', + "`Omit` remove propriedades de um tipo objeto. " + + "`Exclude` remove tipos de uma union. Entenda a diferença.", + task: "Use Omit para objeto e Exclude para union.", + hint: "Omit para objetos, Exclude para unions", starterCode: `interface User { id: number name: string @@ -3485,13 +3485,13 @@ console.log("Primary colors:", primaries)`, }, { id: 92, - title: 'Object.entries e Object.keys Tipados', - level: 'basic', + title: "Object.entries e Object.keys Tipados", + level: "basic", content: - 'Object.entries e Object.keys retornam `string[]` por padrão. ' + - 'Use assertion ou generics para tipá-los corretamente.', - task: 'Itere sobre um objeto com tipos corretos.', - hint: 'Use as Array<[keyof T, T[keyof T]]>', + "Object.entries e Object.keys retornam `string[]` por padrão. " + + "Use assertion ou generics para tipá-los corretamente.", + task: "Itere sobre um objeto com tipos corretos.", + hint: "Use as Array<[keyof T, T[keyof T]]>", starterCode: `interface User { id: number name: string @@ -3526,13 +3526,13 @@ typedEntries({ a: 1, b: 2, c: 3 }).forEach(([k, v]) => { }, { id: 93, - title: 'Strict Property Initialization', - level: 'basic', + title: "Strict Property Initialization", + level: "basic", content: - 'Com strictPropertyInitialization, propriedades de classe devem ser inicializadas ' + - 'no construtor ou com initialization shorthand.', - task: 'Inicialize propriedades corretamente.', - hint: 'Use constructor ou initialization shorthand.', + "Com strictPropertyInitialization, propriedades de classe devem ser inicializadas " + + "no construtor ou com initialization shorthand.", + task: "Inicialize propriedades corretamente.", + hint: "Use constructor ou initialization shorthand.", starterCode: `class User { name: string age: number @@ -3577,13 +3577,13 @@ console.log("Name:", opt.name)`, }, { id: 94, - title: 'Type-safe Fetch Wrapper', - level: 'advanced', + title: "Type-safe Fetch Wrapper", + level: "advanced", content: - 'Crie um wrapper type-safe para fetch que infere o tipo de resposta. ' + - 'Suporta JSON, texto, e verificação de status.', - task: 'Crie uma função fetchJson type-safe.', - hint: 'async function fetchJson(url: string): Promise', + "Crie um wrapper type-safe para fetch que infere o tipo de resposta. " + + "Suporta JSON, texto, e verificação de status.", + task: "Crie uma função fetchJson type-safe.", + hint: "async function fetchJson(url: string): Promise", starterCode: `async function fetchJson( url: string, options?: RequestInit @@ -3634,13 +3634,13 @@ main()`, }, { id: 95, - title: 'Type-safe Route Handler', - level: 'advanced', + title: "Type-safe Route Handler", + level: "advanced", content: - 'Crie um router type-safe onde cada rota tem seu handler com tipos específicos. ' + - 'O handler recebe apenas os parâmetros definidos para aquela rota.', - task: 'Crie handlers de rota type-safe.', - hint: 'Use Record para mapear rotas para handlers.', + "Crie um router type-safe onde cada rota tem seu handler com tipos específicos. " + + "O handler recebe apenas os parâmetros definidos para aquela rota.", + task: "Crie handlers de rota type-safe.", + hint: "Use Record para mapear rotas para handlers.", starterCode: `type RouteHandler = (params: T) => string | Promise interface Route { @@ -3695,12 +3695,12 @@ console.log(matchRoute("/posts/456?draft=true", routes))`, }, { id: 96, - title: 'Generic Record Factory', - level: 'advanced', + title: "Generic Record Factory", + level: "advanced", content: - 'Crie uma factory que gera objetos tipados com métodos úteis. ' + - 'O tipo de retorno deve ser completamente inferido.', - task: 'Crie uma factory para gerar objetos com IDs.', + "Crie uma factory que gera objetos tipados com métodos úteis. " + + "O tipo de retorno deve ser completamente inferido.", + task: "Crie uma factory para gerar objetos com IDs.", hint: 'function create(data: Omit): T & { id: string }', starterCode: `function createEntity( data: T @@ -3756,13 +3756,13 @@ console.log("Numbers:", [...numbers])`, }, { id: 97, - title: 'Reverse Engineering Types', - level: 'advanced', + title: "Reverse Engineering Types", + level: "advanced", content: - 'Dado um objeto, derive seu tipo automaticamente. ' + - 'Use `typeof` para criar tipos a partir de valores.', - task: 'Use typeof para criar tipos a partir de objetos.', - hint: 'type T = typeof myObject', + "Dado um objeto, derive seu tipo automaticamente. " + + "Use `typeof` para criar tipos a partir de valores.", + task: "Use typeof para criar tipos a partir de objetos.", + hint: "type T = typeof myObject", starterCode: `const user = { id: 1, name: "Alice", @@ -3812,12 +3812,12 @@ type Method = typeof constObj.GET | typeof constObj.POST`, }, { id: 98, - title: 'Chaining Optionals', - level: 'basic', + title: "Chaining Optionals", + level: "basic", content: - 'Ao acessar propriedades opcionais aninhadas, você pode usar optional chaining ' + - 'para evitar erros. Aprenda a lidar com undefined em profundidades.', - task: 'Acesse propriedades profundas com safety.', + "Ao acessar propriedades opcionais aninhadas, você pode usar optional chaining " + + "para evitar erros. Aprenda a lidar com undefined em profundidades.", + task: "Acesse propriedades profundas com safety.", hint: 'user?.address?.city ?? "unknown"', starterCode: `interface User { name: string @@ -3861,13 +3861,13 @@ console.log("getCity:", getCity(user1), getCity(user2))`, }, { id: 99, - title: 'Type-safe Event-Driven Architecture', - level: 'advanced', + title: "Type-safe Event-Driven Architecture", + level: "advanced", content: - 'Crie um sistema de eventos onde emissores e listeners são type-safe. ' + - 'O tipo de evento determina os dados disponíveis.', - task: 'Implemente subscribe/publish com tipos derivados.', - hint: 'Use generic para relacionar evento e dados.', + "Crie um sistema de eventos onde emissores e listeners são type-safe. " + + "O tipo de evento determina os dados disponíveis.", + task: "Implemente subscribe/publish com tipos derivados.", + hint: "Use generic para relacionar evento e dados.", starterCode: `type EventMap = { userCreated: { id: number; email: string } userUpdated: { id: number; changes: Record } @@ -3915,14 +3915,14 @@ emitter.emit("userUpdated", { id: 1, changes: { name: "Alice", age: 26 } })`, }, { id: 100, - title: 'Conclusão: Próximos Passos', - level: 'basic', - content: - 'Parabéns por completar 100 lições de TypeScript! Agora você tem uma base sólida. ' + - 'Próximos passos: contribua com projetos open source, explore bibliotecas como React/Next.js, ' + - 'e pratique com desafios de código.', - task: 'Revise o que aprendeu e continue praticando!', - hint: 'Prática leva à maestria!', + title: "Conclusão: Próximos Passos", + level: "basic", + content: + "Parabéns por completar 100 lições de TypeScript! Agora você tem uma base sólida. " + + "Próximos passos: contribua com projetos open source, explore bibliotecas como React/Next.js, " + + "e pratique com desafios de código.", + task: "Revise o que aprendeu e continue praticando!", + hint: "Prática leva à maestria!", starterCode: `console.log("🎉 Parabéns!") console.log("") console.log("Você completou 100 lições de TypeScript!") @@ -3950,13 +3950,13 @@ console.log("Boa jornada! 🚀")`, }, { id: 101, - title: ' typeof com Objetos', - level: 'medium', + title: " typeof com Objetos", + level: "medium", content: - 'Use `typeof` para obter o tipo de uma variável ou objeto. ' + - 'Isso cria um tipo automaticamente baseado no valor.', - task: 'Obtenha o tipo de um objeto usando typeof.', - hint: 'type T = typeof myObject', + "Use `typeof` para obter o tipo de uma variável ou objeto. " + + "Isso cria um tipo automaticamente baseado no valor.", + task: "Obtenha o tipo de um objeto usando typeof.", + hint: "type T = typeof myObject", starterCode: `const user = { name: "Alice", age: 25, @@ -3975,13 +3975,13 @@ console.log("New user:", newUser)`, }, { id: 102, - title: ' Operador && e ||', - level: 'medium', + title: " Operador && e ||", + level: "medium", content: - 'Operadores lógicos funcionam como em JavaScript. ' + - 'Aprenda a usá-los com tipos condicionais.', - task: 'Use operadores lógicos em expressões.', - hint: 'const result = a && b || c', + "Operadores lógicos funcionam como em JavaScript. " + + "Aprenda a usá-los com tipos condicionais.", + task: "Use operadores lógicos em expressões.", + hint: "const result = a && b || c", starterCode: `const a = true const b = false const c = true @@ -4000,13 +4000,13 @@ console.log("OR result:", orResult)`, }, { id: 103, - title: ' Ternary Operator', - level: 'medium', + title: " Ternary Operator", + level: "medium", content: - 'O operador ternário `condição ? valor1 : valor2` é útil para condições simples. ' + - 'Também pode ser usado em tipos com conditional types.', - task: 'Use o operador ternário para escolher valores.', - hint: 'const result = condition ? value1 : value2', + "O operador ternário `condição ? valor1 : valor2` é útil para condições simples. " + + "Também pode ser usado em tipos com conditional types.", + task: "Use o operador ternário para escolher valores.", + hint: "const result = condition ? value1 : value2", starterCode: `const age = 18 const status = age >= 18 ? "adult" : "minor" console.log("Status:", status) @@ -4024,13 +4024,13 @@ console.log(hasItems)`, }, { id: 104, - title: ' Arrow Functions', - level: 'medium', + title: " Arrow Functions", + level: "medium", content: - 'Arrow functions são funções anônimas mais sintéticas. ' + - 'TypeScript infere tipos de parâmetros e retorno.', - task: 'Crie arrow functions tipadas.', - hint: 'const fn = (x: number): number => x * 2', + "Arrow functions são funções anônimas mais sintéticas. " + + "TypeScript infere tipos de parâmetros e retorno.", + task: "Crie arrow functions tipadas.", + hint: "const fn = (x: number): number => x * 2", starterCode: `const add = (a: number, b: number): number => a + b const greet = (name: string): string => \`Hello, \${name}!\` const double = (x: number) => x * 2 @@ -4048,13 +4048,13 @@ console.log(process(numbers, double))`, }, { id: 105, - title: ' Spread em Objetos', - level: 'medium', + title: " Spread em Objetos", + level: "medium", content: - 'O spread operator `...` copia propriedades de objetos. ' + - 'Útil para criar cópias e mesclar objetos.', - task: 'Use spread para mesclar objetos.', - hint: 'const merged = { ...obj1, ...obj2 }', + "O spread operator `...` copia propriedades de objetos. " + + "Útil para criar cópias e mesclar objetos.", + task: "Use spread para mesclar objetos.", + hint: "const merged = { ...obj1, ...obj2 }", starterCode: `const defaults = { theme: "dark", language: "pt-BR" } const userPrefs = { theme: "light" } @@ -4072,13 +4072,13 @@ console.log("Full:", full)`, }, { id: 106, - title: ' Spread em Arrays', - level: 'medium', + title: " Spread em Arrays", + level: "medium", content: - 'Spread em arrays cria novas cópias ou concatena arrays. ' + - 'Não modifica o array original (imutabilidade).', - task: 'Use spread para manipular arrays.', - hint: 'const combined = [...arr1, ...arr2]', + "Spread em arrays cria novas cópias ou concatena arrays. " + + "Não modifica o array original (imutabilidade).", + task: "Use spread para manipular arrays.", + hint: "const combined = [...arr1, ...arr2]", starterCode: `const arr1 = [1, 2, 3] const arr2 = [4, 5, 6] @@ -4097,13 +4097,13 @@ console.log("Doubled:", updated)`, }, { id: 107, - title: ' Destructuring de Objetos', - level: 'medium', + title: " Destructuring de Objetos", + level: "medium", content: - 'Destructuring extrai propriedades de objetos em variáveis. ' + - 'Pode usar valores padrão para propriedades opcionais.', - task: 'Extraia propriedades de um objeto.', - hint: 'const { name, age } = user', + "Destructuring extrai propriedades de objetos em variáveis. " + + "Pode usar valores padrão para propriedades opcionais.", + task: "Extraia propriedades de um objeto.", + hint: "const { name, age } = user", starterCode: `const user = { name: "Alice", age: 25, @@ -4124,13 +4124,13 @@ console.log(greet(user))`, }, { id: 108, - title: ' Destructuring de Arrays', - level: 'medium', + title: " Destructuring de Arrays", + level: "medium", content: - 'Destructuring de arrays usa posição, não nomes. ' + - 'Pode ignorar elementos ou usar rest parameters.', - task: 'Extraia elementos de um array por posição.', - hint: 'const [first, second] = arr', + "Destructuring de arrays usa posição, não nomes. " + + "Pode ignorar elementos ou usar rest parameters.", + task: "Extraia elementos de um array por posição.", + hint: "const [first, second] = arr", starterCode: `const coords = [10, 20, 30] const [x, y, z] = coords console.log("Coords:", x, y, z) @@ -4150,13 +4150,13 @@ console.log("Sum:", sum([5, 3]))`, }, { id: 109, - title: ' Array Methods - map', - level: 'medium', + title: " Array Methods - map", + level: "medium", content: - 'map cria um novo array transformando cada elemento. ' + - 'TypeScript infere o tipo do array resultante.', - task: 'Use map para transformar um array.', - hint: 'const doubled = nums.map(n => n * 2)', + "map cria um novo array transformando cada elemento. " + + "TypeScript infere o tipo do array resultante.", + task: "Use map para transformar um array.", + hint: "const doubled = nums.map(n => n * 2)", starterCode: `const numbers = [1, 2, 3, 4, 5] const doubled = numbers.map(n => n * 2) @@ -4187,13 +4187,13 @@ console.log("Birthdays:", birthdays)`, }, { id: 110, - title: ' Array Methods - filter', - level: 'medium', + title: " Array Methods - filter", + level: "medium", content: - 'filter cria um novo array com elementos que passam no teste. ' + - 'TypeScript refina o tipo automaticamente.', - task: 'Filtre um array usando filter.', - hint: 'const evens = nums.filter(n => n % 2 === 0)', + "filter cria um novo array com elementos que passam no teste. " + + "TypeScript refina o tipo automaticamente.", + task: "Filtre um array usando filter.", + hint: "const evens = nums.filter(n => n % 2 === 0)", starterCode: `const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] const evens = numbers.filter(n => n % 2 === 0) @@ -4225,13 +4225,11 @@ console.log("Under 1000:", affordable)`, }, { id: 111, - title: ' Array Methods - reduce', - level: 'medium', - content: - 'reduce reduz um array a um único valor. ' + - 'O acumulador pode ser qualquer tipo.', - task: 'Some todos os números de um array.', - hint: 'const sum = arr.reduce((acc, n) => acc + n, 0)', + title: " Array Methods - reduce", + level: "medium", + content: "reduce reduz um array a um único valor. " + "O acumulador pode ser qualquer tipo.", + task: "Some todos os números de um array.", + hint: "const sum = arr.reduce((acc, n) => acc + n, 0)", starterCode: `const numbers = [1, 2, 3, 4, 5] const sum = numbers.reduce((acc, n) => acc + n, 0) @@ -4265,13 +4263,13 @@ console.log("By age:", byAge)`, }, { id: 112, - title: ' Array Methods - find e findIndex', - level: 'medium', + title: " Array Methods - find e findIndex", + level: "medium", content: - 'find retorna o primeiro elemento que satisfaz a condição. ' + - 'findIndex retorna sua posição.', - task: 'Encontre um elemento no array.', - hint: 'const found = arr.find(x => x.id === 1)', + "find retorna o primeiro elemento que satisfaz a condição. " + + "findIndex retorna sua posição.", + task: "Encontre um elemento no array.", + hint: "const found = arr.find(x => x.id === 1)", starterCode: `const numbers = [10, 20, 30, 40, 50] const found = numbers.find(n => n > 25) @@ -4299,13 +4297,13 @@ console.log("Index:", userIndex)`, }, { id: 113, - title: ' Array Methods - some e every', - level: 'medium', + title: " Array Methods - some e every", + level: "medium", content: - 'some retorna true se algum elemento passar no teste. ' + - 'every retorna true se todos passarem.', - task: 'Verifique condições em arrays.', - hint: 'const hasEvens = arr.some(n => n % 2 === 0)', + "some retorna true se algum elemento passar no teste. " + + "every retorna true se todos passarem.", + task: "Verifique condições em arrays.", + hint: "const hasEvens = arr.some(n => n % 2 === 0)", starterCode: `const numbers = [1, 3, 5, 7, 9] const hasEvens = numbers.some(n => n % 2 === 0) @@ -4336,13 +4334,13 @@ console.log("All available:", allAvailable)`, }, { id: 114, - title: ' Array Methods - includes e indexOf', - level: 'medium', + title: " Array Methods - includes e indexOf", + level: "medium", content: - 'includes verifica se um valor existe no array. ' + - 'indexOf retorna a posição ou -1 se não encontrar.', - task: 'Verifique se um valor existe no array.', - hint: 'const exists = arr.includes(value)', + "includes verifica se um valor existe no array. " + + "indexOf retorna a posição ou -1 se não encontrar.", + task: "Verifique se um valor existe no array.", + hint: "const exists = arr.includes(value)", starterCode: `const fruits = ["apple", "banana", "orange"] console.log("Has banana:", fruits.includes("banana")) @@ -4367,13 +4365,13 @@ console.log("Unique:", unique([1, 2, 2, 3, 3, 3]))`, }, { id: 115, - title: ' Array Methods - sort', - level: 'medium', + title: " Array Methods - sort", + level: "medium", content: - 'sort ordena elementos no lugar. ' + - 'Para ordenação correta, forneça uma função comparadora.', - task: 'Ordene um array de números.', - hint: 'const sorted = arr.sort((a, b) => a - b)', + "sort ordena elementos no lugar. " + + "Para ordenação correta, forneça uma função comparadora.", + task: "Ordene um array de números.", + hint: "const sorted = arr.sort((a, b) => a - b)", starterCode: `const numbers = [5, 2, 8, 1, 9] const ascending = [...numbers].sort((a, b) => a - b) @@ -4401,13 +4399,13 @@ console.log("By age:", byAge.map(u => u.name))`, }, { id: 116, - title: ' Array Methods - slice e splice', - level: 'medium', + title: " Array Methods - slice e splice", + level: "medium", content: - 'slice retorna uma cópia de uma porção do array. ' + - 'splice remove/substitui elementos no lugar.', - task: 'Extraia e modifique arrays.', - hint: 'const portion = arr.slice(1, 3)', + "slice retorna uma cópia de uma porção do array. " + + "splice remove/substitui elementos no lugar.", + task: "Extraia e modifique arrays.", + hint: "const portion = arr.slice(1, 3)", starterCode: `const numbers = [0, 1, 2, 3, 4, 5] const portion = numbers.slice(1, 4) @@ -4432,13 +4430,11 @@ console.log("After insert:", arr2)`, }, { id: 117, - title: ' Array Methods - flat', - level: 'medium', - content: - 'flat nivela arrays aninhados. ' + - 'flatMap combina map e flat em uma operação.', - task: 'Nivele arrays aninhados.', - hint: 'const flat = nested.flat()', + title: " Array Methods - flat", + level: "medium", + content: "flat nivela arrays aninhados. " + "flatMap combina map e flat em uma operação.", + task: "Nivele arrays aninhados.", + hint: "const flat = nested.flat()", starterCode: `const nested = [1, [2, 3], [4, [5, 6]]] const flat1 = nested.flat() @@ -4460,12 +4456,12 @@ console.log("Doubled + 1:", doubledAndPlusOne)`, }, { id: 118, - title: ' String Methods', - level: 'medium', + title: " String Methods", + level: "medium", content: - 'Strings têm métodos úteis como split, join, trim, etc. ' + - 'TypeScript os trata como métodos de string.', - task: 'Manipule uma string.', + "Strings têm métodos úteis como split, join, trim, etc. " + + "TypeScript os trata como métodos de string.", + task: "Manipule uma string.", hint: "str.split(',').join('-')", starterCode: `const text = " Hello, World! " @@ -4489,13 +4485,13 @@ console.log("Slice:", email.slice(0, 4))`, }, { id: 119, - title: ' Math e Number', - level: 'medium', + title: " Math e Number", + level: "medium", content: - 'Math fornece funções matemáticas úteis. ' + - 'Number tem constantes e métodos para converter.', - task: 'Use Math e Number para operações.', - hint: 'Math.floor(Math.random() * 10)', + "Math fornece funções matemáticas úteis. " + + "Number tem constantes e métodos para converter.", + task: "Use Math e Number para operações.", + hint: "Math.floor(Math.random() * 10)", starterCode: `console.log("Round:", Math.round(4.5)) console.log("Floor:", Math.floor(4.9)) console.log("Ceil:", Math.ceil(4.1)) @@ -4516,13 +4512,11 @@ console.log("IsFinite:", Number.isFinite(Infinity))`, }, { id: 120, - title: ' Date', - level: 'medium', - content: - 'Date representa datas e tempos. ' + - 'Métodos obtêm componentes individuais.', - task: 'Trabalhe com datas.', - hint: 'const now = new Date()', + title: " Date", + level: "medium", + content: "Date representa datas e tempos. " + "Métodos obtêm componentes individuais.", + task: "Trabalhe com datas.", + hint: "const now = new Date()", starterCode: `const now = new Date() console.log("Now:", now) console.log("ISO:", now.toISOString()) @@ -4543,13 +4537,12 @@ console.log("After week:", afterWeek.toDateString())`, }, { id: 121, - title: ' JSON parse e stringify', - level: 'medium', + title: " JSON parse e stringify", + level: "medium", content: - 'JSON.stringify converte objetos para string. ' + - 'JSON.parse converte string para objeto.', - task: 'Serialize e deserialize JSON.', - hint: 'JSON.parse(jsonString)', + "JSON.stringify converte objetos para string. " + "JSON.parse converte string para objeto.", + task: "Serialize e deserialize JSON.", + hint: "JSON.parse(jsonString)", starterCode: `const obj = { name: "Alice", age: 25, @@ -4571,13 +4564,13 @@ console.log("User:", user.name)`, }, { id: 122, - title: ' Promise.all e Promise.race', - level: 'medium', + title: " Promise.all e Promise.race", + level: "medium", content: - 'Promise.all espera todas as promises resolverem. ' + - 'Promise.race retorna a primeira que resolver.', - task: 'Trabalhe com múltiplas promises.', - hint: 'Promise.all([p1, p2])', + "Promise.all espera todas as promises resolverem. " + + "Promise.race retorna a primeira que resolver.", + task: "Trabalhe com múltiplas promises.", + hint: "Promise.all([p1, p2])", starterCode: `const p1 = Promise.resolve(1) const p2 = Promise.resolve(2) const p3 = Promise.resolve(3) @@ -4602,13 +4595,13 @@ Promise.allSettled([fail, success]).then(results => { }, { id: 123, - title: ' try/catch/finally', - level: 'medium', + title: " try/catch/finally", + level: "medium", content: - 'try executa código, catch trata erros, finally executa sempre. ' + - 'TypeScript infere o tipo do erro como unknown.', - task: 'Trate erros com try/catch.', - hint: 'try { } catch (e) { }', + "try executa código, catch trata erros, finally executa sempre. " + + "TypeScript infere o tipo do erro como unknown.", + task: "Trate erros com try/catch.", + hint: "try { } catch (e) { }", starterCode: `function divide(a: number, b: number): number { if (b === 0) throw new Error("Division by zero") return a / b @@ -4636,10 +4629,10 @@ console.log(safeParse("invalid"))`, }, { id: 124, - title: ' throw e Error', - level: 'medium', - content: 'throw lança exceções. ' + 'O tipo Error tem message e name.', - task: 'Lance erros personalizados.', + title: " throw e Error", + level: "medium", + content: "throw lança exceções. " + "O tipo Error tem message e name.", + task: "Lance erros personalizados.", hint: "throw new Error('message')", starterCode: `function validateAge(age: number): void { if (age < 0) { @@ -4671,13 +4664,11 @@ try { }, { id: 125, - title: ' setTimeout e setInterval', - level: 'medium', - content: - 'setTimeout executa após um delay. ' + - 'setInterval executa repetidamente.', - task: 'Agende execução de código.', - hint: 'setTimeout(() => {}, 1000)', + title: " setTimeout e setInterval", + level: "medium", + content: "setTimeout executa após um delay. " + "setInterval executa repetidamente.", + task: "Agende execução de código.", + hint: "setTimeout(() => {}, 1000)", starterCode: `console.log("Before timeout") setTimeout(() => { @@ -4698,13 +4689,11 @@ const interval = setInterval(() => { }, { id: 126, - title: ' clearTimeout e clearInterval', - level: 'medium', - content: - 'clearTimeout cancela um setTimeout. ' + - 'clearInterval para um setInterval.', - task: 'Cancele timers.', - hint: 'clearTimeout(timerId)', + title: " clearTimeout e clearInterval", + level: "medium", + content: "clearTimeout cancela um setTimeout. " + "clearInterval para um setInterval.", + task: "Cancele timers.", + hint: "clearTimeout(timerId)", starterCode: `const timeoutId = setTimeout(() => { console.log("This won't print") }, 1000) @@ -4725,13 +4714,13 @@ const intervalId = setInterval(() => { }, { id: 127, - title: ' Object.keys, values, entries', - level: 'medium', + title: " Object.keys, values, entries", + level: "medium", content: - 'Object.keys retorna chaves, values retorna valores, ' + - 'entries retorna pares [key, value].', - task: 'Itere sobre as propriedades de um objeto.', - hint: 'Object.keys(obj)', + "Object.keys retorna chaves, values retorna valores, " + + "entries retorna pares [key, value].", + task: "Itere sobre as propriedades de um objeto.", + hint: "Object.keys(obj)", starterCode: `const user = { name: "Alice", age: 25, @@ -4752,13 +4741,13 @@ Object.entries(user).forEach(([key, value]) => { }, { id: 128, - title: ' Object.assign', - level: 'medium', + title: " Object.assign", + level: "medium", content: - 'Object.assign copia propriedades de objetos fonte para um destino. ' + - 'É similar ao spread operator.', - task: 'Copie propriedades entre objetos.', - hint: 'Object.assign(target, source)', + "Object.assign copia propriedades de objetos fonte para um destino. " + + "É similar ao spread operator.", + task: "Copie propriedades entre objetos.", + hint: "Object.assign(target, source)", starterCode: `const target = { a: 1 } const source = { b: 2, c: 3 } @@ -4777,13 +4766,13 @@ console.log("Clone:", clone)`, }, { id: 129, - title: ' Object.freeze e seal', - level: 'medium', + title: " Object.freeze e seal", + level: "medium", content: - 'Object.freeze impede adição/modificação de propriedades. ' + - 'Object.sele impede adição mas permite modificação.', - task: 'Torne um objeto imutável.', - hint: 'Object.freeze(obj)', + "Object.freeze impede adição/modificação de propriedades. " + + "Object.sele impede adição mas permite modificação.", + task: "Torne um objeto imutável.", + hint: "Object.freeze(obj)", starterCode: `const obj = { name: "Alice", age: 25 } Object.freeze(obj) @@ -4809,13 +4798,11 @@ console.log("Sealed new prop:", sealed.newProp)`, }, { id: 130, - title: ' Array.isArray', - level: 'medium', - content: - 'Array.isArray verifica se um valor é um array. ' + - 'Útil para type guards.', - task: 'Verifique se algo é um array.', - hint: 'Array.isArray(value)', + title: " Array.isArray", + level: "medium", + content: "Array.isArray verifica se um valor é um array. " + "Útil para type guards.", + task: "Verifique se algo é um array.", + hint: "Array.isArray(value)", starterCode: `console.log("Is array:", Array.isArray([1, 2, 3])) console.log("Not array:", Array.isArray("hello")) console.log("Not array:", Array.isArray({ length: 3 })) @@ -4835,13 +4822,13 @@ process({ 0: "a", 1: "b", length: 2 })`, }, { id: 131, - title: ' Boolean Coercion', - level: 'medium', + title: " Boolean Coercion", + level: "medium", content: - 'Valores podem ser convertidos para boolean com !! ou Boolean(). ' + + "Valores podem ser convertidos para boolean com !! ou Boolean(). " + 'Entenda falsy values: false, 0, "", null, undefined, NaN.', - task: 'Converta valores para boolean.', - hint: 'const bool = !!value', + task: "Converta valores para boolean.", + hint: "const bool = !!value", starterCode: `console.log("Boolean of 1:", Boolean(1)) console.log("Boolean of 0:", Boolean(0)) console.log("Boolean of '':", Boolean("")) @@ -4860,12 +4847,12 @@ console.log("Bool:", bool)`, }, { id: 132, - title: ' Number Coercion', - level: 'medium', + title: " Number Coercion", + level: "medium", content: - 'Converta strings para números com Number(), parseInt(), parseFloat(). ' + - 'Entenda a diferença entre eles.', - task: 'Converta strings para números.', + "Converta strings para números com Number(), parseInt(), parseFloat(). " + + "Entenda a diferença entre eles.", + task: "Converta strings para números.", hint: "Number('42') ou parseInt('42')", starterCode: `console.log("Number('42'):", Number("42")) console.log("Number('3.14'):", Number("3.14")) @@ -4885,12 +4872,12 @@ console.log("+ '3.14':", +"3.14")`, }, { id: 133, - title: ' String Coercion', - level: 'medium', + title: " String Coercion", + level: "medium", content: - 'Converta valores para string com String() ou toString(). ' + - 'Template literals também convertem automaticamente.', - task: 'Converta valores para string.', + "Converta valores para string com String() ou toString(). " + + "Template literals também convertem automaticamente.", + task: "Converta valores para string.", hint: "String(42) ou 42 + ''", starterCode: `console.log("String(42):", String(42)) console.log("String(true):", String(true)) @@ -4910,13 +4897,13 @@ console.log("\`Bool: \${bool}\`:", \`Bool: \${bool}\`)`, }, { id: 134, - title: ' Default Parameters', - level: 'medium', + title: " Default Parameters", + level: "medium", content: - 'Parâmetros com valor padrão são usados quando o argumento é undefined. ' + - 'Diferente de opcionais (?), que podem ser omitidos completamente.', - task: 'Use parâmetros com valor padrão.', - hint: 'function fn(a: number = 10)', + "Parâmetros com valor padrão são usados quando o argumento é undefined. " + + "Diferente de opcionais (?), que podem ser omitidos completamente.", + task: "Use parâmetros com valor padrão.", + hint: "function fn(a: number = 10)", starterCode: `function greet(name: string = "World"): string { return \`Hello, \${name}!\` } @@ -4940,13 +4927,13 @@ console.log(createUser("Charlie", 25))`, }, { id: 135, - title: ' Rest Parameters', - level: 'medium', + title: " Rest Parameters", + level: "medium", content: - 'Rest parameters收集 múltiplos argumentos em um array. ' + - 'Útil para funções com número variável de parâmetros.', - task: 'Crie uma função com rest parameters.', - hint: 'function fn(...args: number[])', + "Rest parameters收集 múltiplos argumentos em um array. " + + "Útil para funções com número variável de parâmetros.", + task: "Crie uma função com rest parameters.", + hint: "function fn(...args: number[])", starterCode: `function sum(...numbers: number[]): number { return numbers.reduce((a, b) => a + b, 0) } @@ -4966,13 +4953,13 @@ console.log("Spread:", sum(...arr))`, }, { id: 136, - title: ' Arguments Object', - level: 'medium', + title: " Arguments Object", + level: "medium", content: - 'arguments é um objeto array-like disponível em funções normais. ' + - 'Arrow functions não têm arguments.', - task: 'Acesse argumentos via arguments.', - hint: 'function fn() { console.log(arguments) }', + "arguments é um objeto array-like disponível em funções normais. " + + "Arrow functions não têm arguments.", + task: "Acesse argumentos via arguments.", + hint: "function fn() { console.log(arguments) }", starterCode: `function sum(): number { let total = 0 for (let i = 0; i < arguments.length; i++) { @@ -4992,13 +4979,11 @@ showArgs(1, "hello", true)`, }, { id: 137, - title: ' IIFE - Immediately Invoked Function', - level: 'medium', - content: - 'IIFE é uma função que executa imediatamente. ' + - 'Útil para criar escopo privado.', - task: 'Crie uma IIFE.', - hint: '(() => { })()', + title: " IIFE - Immediately Invoked Function", + level: "medium", + content: "IIFE é uma função que executa imediatamente. " + "Útil para criar escopo privado.", + task: "Crie uma IIFE.", + hint: "(() => { })()", starterCode: `(function() { const privateVar = "I'm private" console.log("IIFE executed:", privateVar) @@ -5026,13 +5011,13 @@ console.log("Counter:", counter.get())`, }, { id: 138, - title: ' Callback Functions', - level: 'medium', + title: " Callback Functions", + level: "medium", content: - 'Callbacks são funções passadas como argumento para outras funções. ' + - 'Comumente usados em event listeners e array methods.', - task: 'Passe uma função como callback.', - hint: 'arr.forEach((item) => { })', + "Callbacks são funções passadas como argumento para outras funções. " + + "Comumente usados em event listeners e array methods.", + task: "Passe uma função como callback.", + hint: "arr.forEach((item) => { })", starterCode: `function processArray( arr: number[], callback: (n: number) => number @@ -5066,13 +5051,12 @@ withCallback("Alice", (err, result) => { }, { id: 139, - title: ' for...in e for...of', - level: 'medium', + title: " for...in e for...of", + level: "medium", content: - 'for...in itera sobre chaves de objetos. ' + - 'for...of itera sobre valores de iteráveis.', - task: 'Itere sobre objetos e arrays.', - hint: 'for...of para arrays', + "for...in itera sobre chaves de objetos. " + "for...of itera sobre valores de iteráveis.", + task: "Itere sobre objetos e arrays.", + hint: "for...of para arrays", starterCode: `const user = { name: "Alice", age: 25, city: "SP" } console.log("for...in:") @@ -5094,13 +5078,13 @@ for (const [index, num] of numbers.entries()) { }, { id: 140, - title: ' while e do...while', - level: 'medium', + title: " while e do...while", + level: "medium", content: - 'while executa enquanto a condição for verdadeira. ' + - 'do...while executa pelo menos uma vez.', - task: 'Use loops while.', - hint: 'while (condition) { }', + "while executa enquanto a condição for verdadeira. " + + "do...while executa pelo menos uma vez.", + task: "Use loops while.", + hint: "while (condition) { }", starterCode: `let count = 0 while (count < 5) { @@ -5130,13 +5114,11 @@ console.log("Length:", chars)`, }, { id: 141, - title: ' break e continue', - level: 'medium', - content: - 'break sai do loop completamente. ' + - 'continue pula para a próxima iteração.', - task: 'Controle o fluxo de loops.', - hint: 'break para sair, continue para pular', + title: " break e continue", + level: "medium", + content: "break sai do loop completamente. " + "continue pula para a próxima iteração.", + task: "Controle o fluxo de loops.", + hint: "break para sair, continue para pular", starterCode: `for (let i = 1; i <= 10; i++) { if (i === 5) break console.log("i:", i) @@ -5162,13 +5144,11 @@ console.log("Found:", found)`, }, { id: 142, - title: ' Labeled Statements', - level: 'medium', - content: - 'Labels identificam loops para break/continue. ' + - 'Útil para loops aninhados.', - task: 'Use labels para controlar loops aninhados.', - hint: 'label: for (...)', + title: " Labeled Statements", + level: "medium", + content: "Labels identificam loops para break/continue. " + "Útil para loops aninhados.", + task: "Use labels para controlar loops aninhados.", + hint: "label: for (...)", starterCode: `outer: for (let i = 1; i <= 3; i++) { for (let j = 1; j <= 3; j++) { console.log(\`i=\${i}, j=\${j}\`) @@ -5192,12 +5172,10 @@ outer2: while (i < 3) { }, { id: 143, - title: ' typeof operator', - level: 'medium', - content: - 'typeof retorna o tipo de um valor como string. ' + - 'Útil para type guards básicos.', - task: 'Use typeof para verificar tipos.', + title: " typeof operator", + level: "medium", + content: "typeof retorna o tipo de um valor como string. " + "Útil para type guards básicos.", + task: "Use typeof para verificar tipos.", hint: "typeof value === 'string'", starterCode: `console.log("typeof 'hello':", typeof "hello") console.log("typeof 42:", typeof 42) @@ -5220,13 +5198,13 @@ console.log(process(42))`, }, { id: 144, - title: ' instanceof', - level: 'medium', + title: " instanceof", + level: "medium", content: - 'instanceof verifica se um objeto é instância de uma classe. ' + - 'Também funciona para objetos built-in como Array, Date.', - task: 'Use instanceof para verificar classes.', - hint: 'value instanceof Array', + "instanceof verifica se um objeto é instância de uma classe. " + + "Também funciona para objetos built-in como Array, Date.", + task: "Use instanceof para verificar classes.", + hint: "value instanceof Array", starterCode: `class Dog { bark() { return "Woof!" } } @@ -5257,12 +5235,12 @@ process([1, 2, 3])`, }, { id: 145, - title: ' in operator', - level: 'medium', + title: " in operator", + level: "medium", content: - 'in verifica se uma propriedade existe em um objeto. ' + - 'Retorna true para próprias e herdadas (com hasOwnProperty para só próprias).', - task: 'Use in para verificar propriedades.', + "in verifica se uma propriedade existe em um objeto. " + + "Retorna true para próprias e herdadas (com hasOwnProperty para só próprias).", + task: "Use in para verificar propriedades.", hint: "'prop' in object", starterCode: `const user = { name: "Alice", age: 25 } @@ -5291,13 +5269,11 @@ console.log(hasProp(car, "year"))`, }, { id: 146, - title: ' delete operator', - level: 'medium', - content: - 'delete remove propriedades de objetos. ' + - 'Não funciona em variáveis ou funções.', - task: 'Remova propriedades de objetos.', - hint: 'delete object.property', + title: " delete operator", + level: "medium", + content: "delete remove propriedades de objetos. " + "Não funciona em variáveis ou funções.", + task: "Remova propriedades de objetos.", + hint: "delete object.property", starterCode: `const user = { name: "Alice", age: 25, city: "SP" } console.log("Before delete:", user) @@ -5315,13 +5291,13 @@ console.log("'2' in arr:", "2" in arr)`, }, { id: 147, - title: ' void operator', - level: 'medium', + title: " void operator", + level: "medium", content: - 'void avalia uma expressão e retorna undefined. ' + - 'Útil para IIFEs ou previnir navegação em links.', - task: 'Use void operator.', - hint: 'void expression', + "void avalia uma expressão e retorna undefined. " + + "Útil para IIFEs ou previnir navegação em links.", + task: "Use void operator.", + hint: "void expression", starterCode: `console.log("void 0:", void 0) console.log("void 1+1:", void 1 + 1) @@ -5341,13 +5317,13 @@ console.log("Use void for preventDefault")`, }, { id: 148, - title: ' Comma Operator', - level: 'medium', + title: " Comma Operator", + level: "medium", content: - 'A vírgula avalia expressões da esquerda para direita e retorna a última. ' + - 'Útil em loops for e expressões compactas.', - task: 'Use operador vírgula.', - hint: '(a, b, c) - retorna c', + "A vírgula avalia expressões da esquerda para direita e retorna a última. " + + "Útil em loops for e expressões compactas.", + task: "Use operador vírgula.", + hint: "(a, b, c) - retorna c", starterCode: `const result = (1, 2, 3) console.log("Result:", result) @@ -5365,13 +5341,13 @@ console.log("Coords:", coords)`, }, { id: 149, - title: ' Bitwise Operators', - level: 'medium', + title: " Bitwise Operators", + level: "medium", content: - 'Operadores bitwise manipulam bits de números. ' + - 'Útil para flags, criptografia, otimização.', - task: 'Use operadores bitwise.', - hint: '& | ^ ~ << >>', + "Operadores bitwise manipulam bits de números. " + + "Útil para flags, criptografia, otimização.", + task: "Use operadores bitwise.", + hint: "& | ^ ~ << >>", starterCode: `console.log("5 & 3:", 5 & 3) console.log("5 | 3:", 5 | 3) console.log("5 ^ 3:", 5 ^ 3) @@ -5398,12 +5374,12 @@ console.log("After removing A:", flags)`, }, { id: 150, - title: ' eval', - level: 'medium', + title: " eval", + level: "medium", content: - 'eval executa uma string como código JavaScript. ' + - 'Evite usar em código de produção por segurança.', - task: 'Use eval com cuidado.', + "eval executa uma string como código JavaScript. " + + "Evite usar em código de produção por segurança.", + task: "Use eval com cuidado.", hint: "eval('code string')", starterCode: `const code = "2 + 2" console.log("Result:", eval(code)) From b5b514a10059ba9f2812dba4c04c689efb882be1 Mon Sep 17 00:00:00 2001 From: Mostafa Date: Fri, 17 Jul 2026 09:04:08 +0300 Subject: [PATCH 4/4] Fix- lesson 7 name is declare as globale scobe and name is deprecated --- src/data/lessons/lessons-en.ts | 46 ++++++++++++++++++---------------- src/data/lessons/lessons.ts | 46 ++++++++++++++++++---------------- 2 files changed, 48 insertions(+), 44 deletions(-) diff --git a/src/data/lessons/lessons-en.ts b/src/data/lessons/lessons-en.ts index 0e6b7e5..924a900 100644 --- a/src/data/lessons/lessons-en.ts +++ b/src/data/lessons/lessons-en.ts @@ -162,7 +162,8 @@ console.log("Length 2:", length2)`, "type `void` for functions that don't return anything.", task: "Create variables of the types you learned.", hint: 'let name: string = "Alice";', - starterCode: `let name: string = "Alice" + starterCode: `{ +let name: string = "Alice" let age: number = 25 let isStudent: boolean = true let nothing: null = null @@ -170,7 +171,8 @@ let notDefined: undefined = undefined let id: symbol = Symbol("id") let bigNumber: bigint = 9007199254740991n -console.log(name, age, isStudent)`, +console.log(name, age, isStudent) +}`, }, { id: 8, @@ -482,11 +484,11 @@ console.log(trim(text))`, export function add(a: number, b: number): number { return a + b } - + export function multiply(a: number, b: number): number { return a * b } - + export const PI = 3.14159 } @@ -597,12 +599,12 @@ function factorial(n) { if (n < 0) { throw new Error("Number must be non-negative") } - + let result = 1 for (let i = 2; i <= n; i++) { result *= i } - + return result } @@ -622,7 +624,7 @@ console.log("Factorial of 5:", factorial(5))`, declare namespace Utils { function formatDate(date: Date): string function trim(str: string): string - + class HttpClient { constructor(baseUrl: string) get(endpoint: string): Promise @@ -714,7 +716,7 @@ console.log("New Balance:", account.getBalance())`, hint: "class Student extends Person { }", starterCode: `class Person { constructor(public name: string, public age: number) {} - + greet(): string { return \`Hello, I am \${this.name}\` } @@ -1193,22 +1195,22 @@ console.log("Find 1:", repo.findById(1))`, function processInput(input: string): number { const num = Number(input) - + if (isNaN(num)) { throw new Error("Input must be a valid number") } - + if (num < 0) { throw new Error("Number must be positive") } - + return num * 2 } try { const result = processInput("5") console.log("Result:", result) - + const invalidResult = processInput("-3") console.log("This won't print:", invalidResult) } catch (error) { @@ -1256,7 +1258,7 @@ async function main() { console.log("Fetching user data...") const userData = await fetchUser(1) console.log("User:", JSON.stringify(userData)) - + const users = await Promise.all([ fetchUser(1), fetchUser(2), @@ -1992,7 +1994,7 @@ const transitions: Record = { function transition(order: Order, event: OrderEvent): Order { const allowed = transitions[order.state] - + if (!allowed.includes(event.type)) { throw new Error(\`Cannot \${event.type} from \${order.state}\`) } @@ -2159,7 +2161,7 @@ function assertNonNull(value: T, message: string): asserts value is NonNullab function processValue(value: string | number) { assert(typeof value === "number", "Value must be a number") assert(value > 0, "Value must be positive") - + console.log("Value is positive number:", value * 2) } @@ -2418,11 +2420,11 @@ const csvData = \`id,name,email,age function parseCSV(csv: string): T[] { const lines = csv.trim().split("\\n") const headers = lines[0].split(",") - + return lines.slice(1).map(line => { const values = line.split(",") const obj: any = {} - + headers.forEach((header, i) => { let value: string | number = values[i] if (!isNaN(Number(value))) { @@ -2430,7 +2432,7 @@ function parseCSV(csv: string): T[] { } obj[header] = value }) - + return obj as T }) } @@ -2737,7 +2739,7 @@ console.log("Ambient declarations loaded!")`, "Useful in exhaustive switch statements.", task: "Create an exhaustive switch.", hint: "default: const _: never = value", - starterCode: `type Shape = + starterCode: `type Shape = | { kind: "circle"; radius: number } | { kind: "square"; side: number } | { kind: "rectangle"; width: number; height: number } @@ -3683,7 +3685,7 @@ console.log(matchRoute("/posts/456?draft=true", routes))`, ): T & { id: string; createdAt: Date; updatedAt: Date } { const id = crypto.randomUUID() const now = new Date() - + return { ...data, id, @@ -3708,7 +3710,7 @@ const user = createEntity({ name: "Alice", email: "alice@example.com" }) console.log("Product:", product) console.log("User:", user) -function createList(items: T[]): T[] & { +function createList(items: T[]): T[] & { add: (item: T) => void remove: (index: number) => void } { @@ -4678,7 +4680,7 @@ let count = 0 const intervalId = setInterval(() => { count++ console.log("Count:", count) - + if (count === 2) { clearInterval(intervalId) console.log("Stopped at 2") diff --git a/src/data/lessons/lessons.ts b/src/data/lessons/lessons.ts index 4392db0..d366605 100644 --- a/src/data/lessons/lessons.ts +++ b/src/data/lessons/lessons.ts @@ -163,7 +163,8 @@ console.log("Length 2:", length2)`, "tipo `void` para funções que não retornam nada.", task: "Crie variáveis dos tipos aprendidos.", hint: 'let name: string = "Alice";', - starterCode: `let name: string = "Alice" + starterCode: `{ +let name: string = "Alice" let age: number = 25 let isStudent: boolean = true let nothing: null = null @@ -171,7 +172,8 @@ let notDefined: undefined = undefined let id: symbol = Symbol("id") let bigNumber: bigint = 9007199254740991n -console.log(name, age, isStudent)`, +console.log(name, age, isStudent) +}`, }, { id: 8, @@ -483,11 +485,11 @@ console.log(trim(text))`, export function add(a: number, b: number): number { return a + b } - + export function multiply(a: number, b: number): number { return a * b } - + export const PI = 3.14159 } @@ -598,12 +600,12 @@ function factorial(n) { if (n < 0) { throw new Error("Number must be non-negative") } - + let result = 1 for (let i = 2; i <= n; i++) { result *= i } - + return result } @@ -623,7 +625,7 @@ console.log("Fatorial de 5:", factorial(5))`, declare namespace Utils { function formatDate(date: Date): string function trim(str: string): string - + class HttpClient { constructor(baseUrl: string) get(endpoint: string): Promise @@ -715,7 +717,7 @@ console.log("New Balance:", account.getBalance())`, hint: "class Student extends Person { }", starterCode: `class Person { constructor(public name: string, public age: number) {} - + greet(): string { return \`Olá, sou \${this.name}\` } @@ -1194,22 +1196,22 @@ console.log("Find 1:", repo.findById(1))`, function processInput(input: string): number { const num = Number(input) - + if (isNaN(num)) { throw new Error("Input must be a valid number") } - + if (num < 0) { throw new Error("Number must be positive") } - + return num * 2 } try { const result = processInput("5") console.log("Result:", result) - + const invalidResult = processInput("-3") console.log("This won't print:", invalidResult) } catch (error) { @@ -1257,7 +1259,7 @@ async function main() { console.log("Fetching user data...") const userData = await fetchUser(1) console.log("User:", JSON.stringify(userData)) - + const users = await Promise.all([ fetchUser(1), fetchUser(2), @@ -1993,7 +1995,7 @@ const transitions: Record = { function transition(order: Order, event: OrderEvent): Order { const allowed = transitions[order.state] - + if (!allowed.includes(event.type)) { throw new Error(\`Cannot \${event.type} from \${order.state}\`) } @@ -2178,7 +2180,7 @@ function assertNonNull(value: T, message: string): asserts value is NonNullab function processValue(value: string | number) { assert(typeof value === "number", "Value must be a number") assert(value > 0, "Value must be positive") - + console.log("Value is positive number:", value * 2) } @@ -2442,11 +2444,11 @@ const csvData = \`id,name,email,age function parseCSV(csv: string): T[] { const lines = csv.trim().split("\\n") const headers = lines[0].split(",") - + return lines.slice(1).map(line => { const values = line.split(",") const obj: any = {} - + headers.forEach((header, i) => { let value: string | number = values[i] if (!isNaN(Number(value))) { @@ -2454,7 +2456,7 @@ function parseCSV(csv: string): T[] { } obj[header] = value }) - + return obj as T }) } @@ -2761,7 +2763,7 @@ console.log("Ambient declarations loaded!")`, "Útil em switch statements exaustivos.", task: "Crie um switch exaustivo.", hint: "default: const _: never = value", - starterCode: `type Shape = + starterCode: `type Shape = | { kind: "circle"; radius: number } | { kind: "square"; side: number } | { kind: "rectangle"; width: number; height: number } @@ -3707,7 +3709,7 @@ console.log(matchRoute("/posts/456?draft=true", routes))`, ): T & { id: string; createdAt: Date; updatedAt: Date } { const id = crypto.randomUUID() const now = new Date() - + return { ...data, id, @@ -3732,7 +3734,7 @@ const user = createEntity({ name: "Alice", email: "alice@example.com" }) console.log("Product:", product) console.log("User:", user) -function createList(items: T[]): T[] & { +function createList(items: T[]): T[] & { add: (item: T) => void remove: (index: number) => void } { @@ -4705,7 +4707,7 @@ let count = 0 const intervalId = setInterval(() => { count++ console.log("Count:", count) - + if (count === 2) { clearInterval(intervalId) console.log("Stopped at 2")