{"id":13660907,"url":"https://github.com/KonstantinSimeonov/tsx-control-statements","last_synced_at":"2025-04-24T23:31:02.530Z","repository":{"id":31875337,"uuid":"127186832","full_name":"KonstantinSimeonov/tsx-control-statements","owner":"KonstantinSimeonov","description":"Control flow JSX/TSX elements that get compiled to plain old javascript.","archived":false,"fork":false,"pushed_at":"2024-01-04T11:00:46.000Z","size":2115,"stargazers_count":94,"open_issues_count":4,"forks_count":9,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-09T14:09:43.889Z","etag":null,"topics":["conditional-rendering","control-statements","if","jsx","loop","react","transformer","tsx","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"wtfpl","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KonstantinSimeonov.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-03-28T19:15:06.000Z","updated_at":"2024-12-26T16:25:30.000Z","dependencies_parsed_at":"2024-01-15T20:51:38.259Z","dependency_job_id":"bfb09dda-1298-4634-a47b-65bc44932c4c","html_url":"https://github.com/KonstantinSimeonov/tsx-control-statements","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KonstantinSimeonov%2Ftsx-control-statements","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KonstantinSimeonov%2Ftsx-control-statements/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KonstantinSimeonov%2Ftsx-control-statements/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KonstantinSimeonov%2Ftsx-control-statements/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KonstantinSimeonov","download_url":"https://codeload.github.com/KonstantinSimeonov/tsx-control-statements/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250727520,"owners_count":21477324,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["conditional-rendering","control-statements","if","jsx","loop","react","transformer","tsx","typescript"],"created_at":"2024-08-02T05:01:27.275Z","updated_at":"2025-04-24T23:31:02.125Z","avatar_url":"https://github.com/KonstantinSimeonov.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# tsx-control-statements\n\n[![CI](https://github.com/KonstantinSimeonov/tsx-control-statements/actions/workflows/ci.yml/badge.svg)](https://github.com/KonstantinSimeonov/tsx-control-statements/actions/workflows/ci.yml) [![Coverage Status](https://coveralls.io/repos/github/KonstantinSimeonov/tsx-control-statements/badge.svg?branch=master)](https://coveralls.io/github/KonstantinSimeonov/tsx-control-statements?branch=master)\n\n[![NPM](https://nodei.co/npm/tsx-control-statements.png)](https://npmjs.org/package/tsx-control-statements)\n\nBasically [jsx-control-statements](https://www.npmjs.com/package/babel-plugin-jsx-control-statements), but for the typescript compiler toolchain. **Works for both javascript and typescript.**\n\n| Typescript version range | `tsx-control-statements` version           |\n|:------------------------:|:-------------------------------------------|\n| `2.4.x` - `3.3.x`        | `v3.3.x`                                   |\n| `3.4.x` - `4.6.x`        | `v4.x`                                     |\n| `4.9`                    | `v5.0`                                     |\n| `5.x`                    | `\u003e= v5.1`                                  |\n\n## Drop-in replacement for jsx control statements\n- No need to rewrite anything\n- Compile control statements in typescript `.tsx` files\n  - Control statements transpile to type-correct typescript before type checking\n- Compile control statements in javascript `.js` and `.jsx` files\n  - `\"allowJs\"` should be set to `true` in your typescript configuration\n- Run the test suite: `npm i \u0026\u0026 npm run build \u0026\u0026 npm run test`. It includes:\n  - Compatibility tests with `jsx-control-statements` (i.e. both produce the same output html)\n  - Tests for correct transpilation\n  - Tests for typechecking\n\n## Zero dependencies apart from typescript\n- Pick any typescript version equal to or above `2.4.x`\n- Can be used with Vue, React or just plain jsx/tsx\n\n## Known limitations:\n- **[js, ts]** I haven't found any way of integrating this into `create-react-app` scaffold project without ejecting the scripts and modifying them\n- **[js, ts]** Various CLIs (`tsc`, `ts-register`, `ts-node`) feature no flag (that I know of) that allows for addition of custom transformers\n- ~~**[ts]** The `isolatedModules` flag currently causes build errors for typescript files, since the typings currently live in a namespace~~\n  - `isolatedModules` is supported since the module `tsx-control-statements/components` contains stub definitions which can be imported `import { For, If } from 'tsx-control-statements/components'`\n- **[ts]** Cannot work with various \"smart\" plugins that instead of invoking the typescript compiler rather strip the types and handle the code as javascript. This includes tools like:\n  - `@babel/preset-typescript`\n  - `@babel/plugin-transform-typescript`\n\n## What are the control statements transpiled to?\n\n### If - Ternary operators\n\n```tsx\nimport { If } from 'tsx-control-statements/components';\n\nconst SongRelatedThingy = ({ songList }: { songList: string[] }) =\u003e (\n  \u003cp\u003e\n    \u003cIf condition={songList.includes('Gery-Nikol - Im the Queen')}\u003e\n      good taste in music\n    \u003c/If\u003e\n  \u003c/p\u003e\n);\n\n// will transpile to\nconst SongRelatedThingy = ({ songList }) =\u003e (\n  \u003cp\u003e\n    {songList.includes('Gery-Nikol - Im the Queen')\n      ? 'good taste in music'\n      : null}\n  \u003c/p\u003e\n);\n```\n\n### With - Immediately invoked function expression\n\n```tsx\nimport { With } from 'tsx-control-statements/components';\n\nconst Sum = () =\u003e (\n  \u003cp\u003e\n    \u003cWith a={3} b={5} c={6}\u003e\n      {a + b + c}\n    \u003c/With\u003e\n  \u003c/p\u003e\n);\n\n// becomes\nconst Sum = () =\u003e \u003cp\u003e{((a, b, c) =\u003e a + b + c)(3, 5, 6)}\u003c/p\u003e;\n```\n\n### For - `Array.from` calls\nMore flexible than `[].map`, since it can be provided with an iterator or an array-like as it's first parameter. For non-legacy code, prefer the more type-safe alternative.\n```tsx\nimport { For } from 'tsx-control-statements/components';\n\n// more type-safe for, the typechecker knows\n// the types of the \"name\" and \"i\" bindings\nconst Names = ({ names }: { names: string[] }) =\u003e (\n  \u003col\u003e\n    \u003cFor\n      of={names}\n      body={(name, i) =\u003e (\n        \u003cli key={name}\u003e\n          {i}\n          \u003cstrong\u003e{name}\u003c/strong\u003e\n        \u003c/li\u003e\n      )}\n    /\u003e\n  \u003c/ol\u003e\n);\n\n// jsx-control-statements compatible\nconst Names = ({ names }: { names: string[] }) =\u003e (\n  \u003col\u003e\n    \u003cFor each=\"name\" of={names} index=\"i\"\u003e\n      \u003cli key={name}\u003e\n        {i}\n        \u003cstrong\u003e{name}\u003c/strong\u003e\n      \u003c/li\u003e\n    \u003c/For\u003e\n  \u003c/ol\u003e\n);\n\n// both of the above will transpile to:\nconst Names = ({ names }) =\u003e (\n  \u003col\u003e\n    {Array.from(names, (name, i) =\u003e (\n      \u003cli key={name}\u003e\n        {i}\n        \u003cstrong\u003e{name}\u003c/strong\u003e\n      \u003c/li\u003e\n    ))}\n  \u003c/ol\u003e\n);\n```\n\n### Choose/When/Otherwise - nested ternary operators, emulates switch/case.\n\n```tsx\nimport {\n  Choose,\n  When,\n  Otherwise\n} from 'tsx-control-statements/components';\n\nconst RandomStuff = ({ str }: { str: string }) =\u003e (\n  \u003carticle\u003e\n    \u003cChoose\u003e\n      \u003cWhen condition={str === 'ivan'}\u003eivancho\u003c/When\u003e\n      \u003cWhen condition={str === 'sarmi'}\u003e\n        \u003ch1\u003eyum!\u003c/h1\u003e\n      \u003c/When\u003e\n      {/* Otherwise tag is optional,\n        * if not provided, null will be rendered */}\n      \u003cOtherwise\u003eim the queen da da da da\u003c/Otherwise\u003e\n    \u003c/Choose\u003e\n  \u003c/article\u003e\n);\n\n// transpiles to\nconst RandomStuff = ({ str }) =\u003e (\n  \u003carticle\u003e\n    {str === 'ivan'\n      ? 'ivancho'\n      : str === 'sarmi'\n        ? React.createElement('h1', null, 'yum!')\n        : 'im the queen da da da da'}\n  \u003c/article\u003e\n);\n```\n\n## Cookbook\n\n#### Bundlers and scaffolding tools\n- `webpack` with [`ts-loader`](https://github.com/TypeStrong/ts-loader#getcustomtransformers)\n- `rollup` with [typescript plugin](https://github.com/rollup/plugins/tree/master/packages/typescript#transformers)\n- `parcel` - [this](https://github.com/coreoz/parcel-transformer-ttypescript) might work but don't count on it\n\n#### Testing\n- `ava`, `mocha` or anything other that can use `ts-node` - `ts-node` supports [programatically adding custom transformers](https://github.com/TypeStrong/ts-node#programmatic-only-options) so it can be used to run test suites.\n- `jest` using `ts-jest` like [that](https://kulshekhar.github.io/ts-jest/docs/getting-started/options/astTransformers)\n\n#### Importing the transformer in your build configs:\n```ts\n// commonjs\nconst transformer = require('tsx-control-statements').default;\n\n// ts\nimport transformer from 'tsx-control-statements';\n```\n\n#### Importing type definitions:\n\n```ts\nimport {\n    For,\n    If,\n    With,\n    Choose,\n    When,\n    Otherwise\n} from 'tsx-control-statements/components';\n```\n\n## Reasons to not use any control statements for jsx:\n- ~~Hard to statically type~~\n  - Has been somewhat adressed, with the exception of `With`\n- Not part of the standard\n- Not ordinary jsx elements\n- Requires extra dependencies to use\n- Many typescript tools do not support custom transformers in a convenient way\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKonstantinSimeonov%2Ftsx-control-statements","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FKonstantinSimeonov%2Ftsx-control-statements","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKonstantinSimeonov%2Ftsx-control-statements/lists"}