# type-challenges: an online judge for TypeScript type puzzles, with nothing on npm

> Every challenge is a numbered folder under questions/ graded by the site at tsch.js.org, and the manifest marks the package private, so type-challenges is a practice corpus with contributor tooling rather than a library you can install.

**type-challenges/type-challenges** — Collection of TypeScript type challenges with online judge

- Repository: https://github.com/type-challenges/type-challenges
- Website: https://tsch.js.org/
- Stars: 48,518 · Forks: 5,263
- Language: TypeScript
- License: MIT
- Published: 2026-08-17 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/type-challenges-type-challenges

## The questions/ tree is the syllabus and the number prefix is the difficulty

Every challenge is a directory under questions/ carrying its own README, and the numeric prefix is the only difficulty signal you get. 00013-warm-hello-world is the warmup, 00004-easy-pick, 00189-easy-awaited and 00043-easy-exclude are the easy tier, and 00002-medium-return-type, 00009-medium-deep-readonly and 00020-medium-promise-all are the medium tier. Index links resolve to paths such as `questions/00004-easy-pick/README.md`, so browsing the site is browsing the folder tree.

The consequence for a learner is that nothing sequences the set. No file declares which question comes after which, and the numeric prefixes are issue-style identifiers rather than a curriculum, so 00002 sits in the medium tier while 00004 is easy. Choosing what to solve next means scanning filenames. The single warmup folder is the only hint about where to begin.

## Grading assumes strict mode, so a loose tsconfig changes the verdict

One line states the precondition, and it links to the TypeScript config reference for the setting. Challenges work in strict mode. That single flag decides whether your answer passes, and a solution leaning on implicit any, on optional properties, or on index signatures that widen quietly can compile in your project and still be rejected at tsch.js.org.

The repository ships tsconfig.base.json and tsconfig.json at the root, and it does not document which of the two the site applies to a submitted answer. A green run of your own compiler is therefore not evidence of anything the judge will agree with. If you want a local signal, mirror the strict setting in your own tsconfig before you paste anything.

## The manifest sets private to true, so nothing is published to npm

The head of the repository manifest is explicit about the distribution story:

```json
{
  "name": "type-challenges",
  "version": "0.0.0",
  "private": true,
  "packageManager": "pnpm@8.12.1"
}
```

The private flag is what blocks publication and 0.0.0 is a placeholder, not a version you can pin. A search of the npm registry for type-challenges will not surface this corpus, and adding it to a dependency list is a no-op. The one workspace package with a release path sits in utils/ and is reached through the utils:release script, which runs `pnpm -C utils release`. If you want these type helpers in production code, this is the wrong repository, and the alternative named in the project README is type-fest.

## Six scripts build the site and none of them tests your answer

For contributors the entire toolchain is the scripts block, and there is no test entry among it:

```json
"readme": "esno ./scripts/readme.ts",
"build": "esno ./scripts/build.ts",
"generate": "esno ./scripts/generate-play.ts",
"lint": "eslint .",
"translate": "esno ./scripts/translate-cli.ts",
"utils:release": "pnpm -C utils release"
```

Two details decide how you work. First, no script grades a candidate answer, so validation happens by pasting into the judge at tsch.js.org and reading the result there. Second, the readme script exists because the question wall in the index is generated: the index file carries a `<!--challenges-start-->` marker with the question links inside it. Drop a folder into questions/ and the index will not show it until that script runs. The build and generate-play scripts feed the site directory that serves the judge.

## Two routes in, and neither of them is an install command

The first documented route is the playground plugin, reached through a link that opens the TypeScript playground with the plugin already selected:

```
https://www.typescriptlang.org/play?install-plugin=%40type-challenges%2Fplayground-plugin
```

That gives you a browser editor and the challenge list without touching a local checkout. The second route is the site itself at tsch.js.org, the online judge where a candidate answer gets its verdict. No clone or install step appears anywhere in the project, and the six scripts above are the whole contributor entry point, so working from source means reading package.json and running whatever you need with the declared pnpm version.

The dependency list tells you what a source checkout pulls in: esno, fast-glob, fs-extra, js-yaml and lz-string at runtime for the scripts, with prompts and ansis on the command line side. lz-string sits in the runtime dependencies next to js-yaml and the build script that serves the judge, yet the project does not document how a solution is encoded into a shareable link, so the URL format is only discoverable by reading site/ and the scripts.

## Translated indexes exist, translated problem statements do not

Four localized indexes sit at the root: README.zh-CN.md, README.ja.md, README.ko.md and README.pt-BR.md, and the translate script is wired up to regenerate them. The problem statements are a separate matter. Every question link resolves to a README.md inside its own folder, and the repository listing shows no translated copies inside those folders, so a reader working in Japanese or Korean gets a local index and English challenge text. The prompts dependency that backs the translate script is the interactive side of that workflow, and it is a developer tool rather than something a learner needs.

Two other root entries are worth opening before you start: TODOs.md, which records what is still open, and guides/, which holds longer material than a single question deserves.

## type-fest ships the answers, the stale packages only lend you the technique

type-fest is the difference in approach, and the project README puts it first among the things to read. It is a library of utilities you install and import, so a type lands in your codebase as a dependency. Here every answer is something you write yourself in a scratch file, and nothing in the repository produces runtime code, because the subject is entirely the compile step.

The same README names utility-types, ts-toolbelt and SimplyTyped and labels them as stale packages that are not actively maintained. That wording matters for a reader deciding what to copy from: these are reference implementations whose maintainers the project itself has flagged, so borrowing a pattern is fine and depending on them is a decision you have to justify. Note that utility-types still appears in this repository's own devDependencies at ^3.10.0, which means its types are in play while the scripts are being developed.

## No releases and a last push on 2026-05-16 leave nothing to pin

The repository has no GitHub releases, the manifest version is 0.0.0, and the last push was on 2026-05-16. It is not archived, so commits still land, but a team that copies a question into an internal exercise set has no tag to diff against and no release to roll forward on. You maintain your own copy of the folder and the answer beside it.

The toolchain is pinned loosely as well. typescript is at ^5.3.3 and eslint at ^8.56.0 with @antfu/eslint-config at ^2.6.0, and the lint script runs `eslint .` across the tree. A solution that a newer TypeScript release accepts can fail against the compiler these scripts are written for, and the caret ranges leave the patch level unpinned, so the exact compiler that judges your answer is not fixed by the repository.

## Conclusion

Adopt type-challenges if you learn TypeScript by writing types and want a verdict on your answer without a mentor in the room. Skip it if you need shipped type helpers in production code, because the package is private and the alternative named in the project README is type-fest. Verify first that your editor runs the same strict settings the judge applies, since every question assumes strict mode.

## FAQ

### What are the different types of challenges?

The question folders are tiered by numeric prefix: 00013-warm-hello-world sits above the easy tier, which includes 00004-easy-pick, 00189-easy-awaited and 00043-easy-exclude, while the medium tier runs from 00002-medium-return-type through 00009-medium-deep-readonly and 00020-medium-promise-all. Each one is its own folder with a README under questions/.

### What are examples of challenges?

Named examples in the easy tier are easy-pick, easy-readonly, easy-tuple-to-object, easy-first, easy-tuple-length, easy-exclude, easy-awaited, easy-if, easy-concat, easy-includes, easy-push, easy-unshift and easy-parameters. The medium tier includes medium-omit, medium-readonly-2, medium-deep-readonly, medium-promise-all and medium-type-lookup.

### Can I install type-challenges from npm and use its types in my project?

No. The manifest sets private to true with version 0.0.0, so nothing is published under that name. The only release path in the repository is pnpm -C utils release, which builds the utils workspace package.

### Do I need strict mode enabled to solve the type-challenges questions?

Yes. The project states that challenges work in strict mode, with a link to the TypeScript config reference for that setting. A solution that only compiles with the flag off will not match what the online judge accepts.

### Is there a local command that checks whether my solution passes?

There is no test script in the manifest. The root scripts are readme, build, generate, lint, translate and utils:release, so grading happens by pasting the candidate answer into the online judge at tsch.js.org.

## Sources

- [Official documentation](https://tsch.js.org/)
- [Official README](https://github.com/type-challenges/type-challenges#readme)
- [Project repository](https://github.com/type-challenges/type-challenges)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/type-challenges-type-challenges
