From 19821e30d18be390beab689bab52d14c451733e9 Mon Sep 17 00:00:00 2001
From: Alexey Berezin <2991847+Beraliv@users.noreply.github.com>
Date: Wed, 18 Dec 2024 20:20:27 +0000
Subject: [PATCH] docs: Applications from popular libraries (#1)
* docs: added 8 zod applications
* feat: conjunction
* feat: applications in CodeExample
* feat: add githubStars
* docs: todo for intrinsic types
* docs: added 2 react-router applications
* docs: applications todo
* docs: added 5 rxjs applications
* docs: added 2 jest applications
* docs: added array to object application from ts-pattern
* refactor: move Projects to a separate React component
* refactor: make applications required
* docs: added 5 prisma, 3 typeorm, 1 redux, 1 trpc & 1 ts-pattern applications
* docs: tick a feature
* docs: added 2 typeorm applications
* docs: intro update
* docs: add 3 safe-units applications
* docs: added 1 prisma application
* docs: added 1 zod application
* docs: added 1 prisma & 2 type-fest applications
* refactor: update conjunction
* feat: added breadcrumbs for zod applications
* feat: added breadcrumbs for prisma applications
* feat: added breadcrumbs for rxjs applications
* feat: added breadcrumbs to ts-pattern applications
* feat: added breadcrumbs for jest applications
* feat: added breadcrumbs to typeorm applications
* feat: added breadcrumbs to dot-path-value applications
* feat: added breadcrumbs to @reduxjs/toolkit applications
* feat: added breadcrumbs to 2 type-fest & 2 react-router applications
* feat: added breadcrumbs to 3 trpc applications
* feat: added breadcrumbs to safe-units applications
---
README.md | 6 +-
src/components/App.tsx | 2 +
src/components/Projects.tsx | 69 ++
.../notes/TailRecursionEliminationNote.tsx | 11 +-
src/utils/conjunction.ts | 21 +
src/utils/map.tsx | 883 +++++++++++++++++-
6 files changed, 981 insertions(+), 11 deletions(-)
create mode 100644 src/components/Projects.tsx
create mode 100644 src/utils/conjunction.ts
diff --git a/README.md b/README.md
index 6a3f480..319a3bf 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# ts-conversion
-Interactive website, helping engineers understand, how they can convert one type to another in TypeScript, with examples and links to TypeScript playground.
+Interactive website, helping understand, how to convert one type to another in TypeScript, with code examples, links to TypeScript playground and applications from popular libraries
Try it now: https://ts-conversion.beraliv.com
@@ -15,14 +15,14 @@ npm install
To start developing the project, run the dev command:
```bash
-npm run dev --host
+npm run dev -- --host
```
## Features
- [x] 36 conversions in total
- [x] Code snippets and links to TypeScript Playground
-- [ ] Applications from popular libraries ([_in progress_](https://github.com/Beraliv/ts-conversion/pull/1))
+- [x] Applications from popular libraries
- [x] A list of insights
- [x] Notes with definitions and links to TypeScript documentation
- [x] Warnings, which highlight potential issues and how to mitigate them
diff --git a/src/components/App.tsx b/src/components/App.tsx
index c401a30..07b9bb4 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -9,6 +9,7 @@ import { NoExampleWarning } from "./NoExampleWarning";
import { UserInput } from "./UserInput";
import style from "./App.module.css";
+import { Projects } from "./Projects";
function App() {
useTrackPage();
@@ -27,6 +28,7 @@ function App() {
<>
+
>
diff --git a/src/components/Projects.tsx b/src/components/Projects.tsx
new file mode 100644
index 0000000..13ca79a
--- /dev/null
+++ b/src/components/Projects.tsx
@@ -0,0 +1,69 @@
+import { useContext } from "react";
+import { map } from "../utils/map";
+import { UserInputContext } from "../contexts/UserInputContext";
+import { Link } from "./Link";
+import { conjunction } from "../utils/conjunction";
+// import { ArrowIcon } from "./icons/ArrowIcon";
+
+export const Projects = () => {
+ const { source, target } = useContext(UserInputContext);
+
+ if (!source || !target || map[source][target] === "empty") {
+ return null;
+ }
+
+ return (
+ <>
+ {map[source][target].applications.length > 0 && (
+
+
Projects
+
Links to the libraries that already use this conversion:
+
+ {map[source][target].applications.map((application, i) => (
+ -
+ {application.library && (
+
+ {application.library}
+ {": "}
+
+ )}
+
+ {application.breadcrumbs &&
+ application.breadcrumbs.map(
+ (breadcrumb, j, breadcrumbs) => (
+ <>
+
+
+ {conjunction(j, breadcrumbs, {
+ last: "",
+ secondToLast: (
+ <>
+ {" "}
+ {/* */}
+ {">"}{" "}
+ >
+ ),
+ others: (
+ <>
+ {" "}
+ {/* */}
+ {">"}{" "}
+ >
+ ),
+ })}
+ >
+ )
+ )}
+
+
+ ))}
+
+
+ )}
+ >
+ );
+};
diff --git a/src/components/notes/TailRecursionEliminationNote.tsx b/src/components/notes/TailRecursionEliminationNote.tsx
index e5e2746..70de43d 100644
--- a/src/components/notes/TailRecursionEliminationNote.tsx
+++ b/src/components/notes/TailRecursionEliminationNote.tsx
@@ -1,3 +1,4 @@
+import { conjunction } from "../../utils/conjunction";
import { Link } from "../Link";
interface TailRecursionEliminationNoteProps {
@@ -20,11 +21,11 @@ export const TailRecursionEliminationNote = ({
{props.map(({ parameterType, utilityType }, index) => (
{parameterType}
in {utilityType}
- {index === props.length - 2
- ? " and "
- : index === props.length - 1
- ? ""
- : ", "}
+ {conjunction(index, props, {
+ last: "",
+ secondToLast: " and ",
+ others: ", ",
+ })}
))}
>
diff --git a/src/utils/conjunction.ts b/src/utils/conjunction.ts
new file mode 100644
index 0000000..d67fd17
--- /dev/null
+++ b/src/utils/conjunction.ts
@@ -0,0 +1,21 @@
+type ConjunctionOptions = {
+ last: JSX.Element | string;
+ secondToLast: JSX.Element | string;
+ others: JSX.Element | string;
+};
+
+export const conjunction = (
+ index: number,
+ array: T[],
+ options: ConjunctionOptions
+): JSX.Element | string => {
+ if (index === array.length - 2) {
+ return options.secondToLast;
+ }
+
+ if (index === array.length - 1) {
+ return options.last;
+ }
+
+ return options.others;
+};
diff --git a/src/utils/map.tsx b/src/utils/map.tsx
index 95fa055..42350f7 100644
--- a/src/utils/map.tsx
+++ b/src/utils/map.tsx
@@ -19,6 +19,14 @@ type MapConfigWithExample = {
type: MessageProps["type"];
}[];
playgroundUrl?: string;
+ applications: {
+ library: string;
+ breadcrumbs: {
+ text: string;
+ href: string;
+ }[];
+ githubStars?: number;
+ }[];
};
type MapConfigWithoutExample = "empty";
@@ -32,7 +40,12 @@ const DistributiveConditionalTypes = () => (
/>
);
-// TODO: examples from real libraries
+// TODO: applications from projects: xstate, lodash
+
+// TODO: applications for examples: Opaque, Range, Repeat, Path, CamelCase,
+// UnionToIntersection, LengthOf, ElementOf
+
+// TODO: intrinsic types
export const map: Record> = {
array: {
array: {
@@ -53,6 +66,18 @@ export const map: Record> = {
// ^? {childrenNames: string[]; name: string; parentsNames: string[]}
`,
playgroundUrl: "https://tsplay.dev/W4DAaW",
+ applications: [
+ {
+ library: "prisma",
+ breadcrumbs: [
+ {
+ text: "Utils.PayloadToResult",
+ href: "https://github.com/prisma/prisma/blob/8957496bd9b24c3ad49d998d51c3d52912aa90d7/packages/client/src/runtime/core/types/exported/Utils.ts#L99-L105",
+ },
+ ],
+ githubStars: 40_100,
+ },
+ ],
insights: [
{
Element: (
@@ -83,6 +108,18 @@ export const map: Record> = {
// ^? [1, 2, 3, 4]
`,
playgroundUrl: "https://tsplay.dev/WJPERN",
+ applications: [
+ {
+ library: "rxjs",
+ breadcrumbs: [
+ {
+ text: "combineLatest",
+ href: "https://github.com/ReactiveX/rxjs/blob/05894120a55e6339a29ee74ec6ae2ee593af5704/packages/rxjs/src/internal/observable/combineLatest.ts#L26-L29",
+ },
+ ],
+ githubStars: 30_900,
+ },
+ ],
insights: [
{
Element: (
@@ -121,6 +158,22 @@ export const map: Record> = {
// ^? {age: number}
`,
playgroundUrl: "https://tsplay.dev/NaxJnw",
+ applications: [
+ {
+ library: "ts-pattern",
+ breadcrumbs: [
+ {
+ text: "array",
+ href: "https://github.com/gvergnaud/ts-pattern/blob/d3284224b47a4ac6f8ccdc244d01190312c7ab27/src/patterns.ts#L218-L221",
+ },
+ {
+ text: "UnwrapArray",
+ href: "https://github.com/gvergnaud/ts-pattern/blob/d3284224b47a4ac6f8ccdc244d01190312c7ab27/src/patterns.ts#L197",
+ },
+ ],
+ githubStars: 12_600,
+ },
+ ],
insights: [
{
Element: ,
@@ -152,6 +205,22 @@ export const map: Record> = {
// ^? number | string
`,
playgroundUrl: "https://tsplay.dev/mqlBrN",
+ applications: [
+ {
+ library: "rxjs",
+ breadcrumbs: [
+ {
+ text: "of",
+ href: "https://github.com/ReactiveX/rxjs/blob/05894120a55e6339a29ee74ec6ae2ee593af5704/packages/rxjs/src/internal/observable/of.ts#L15",
+ },
+ {
+ text: "ValueFromArray",
+ href: "https://github.com/ReactiveX/rxjs/blob/05894120a55e6339a29ee74ec6ae2ee593af5704/packages/rxjs/src/internal/types.ts#L296",
+ },
+ ],
+ githubStars: 30_900,
+ },
+ ],
},
stringLiteral: "empty",
numericLiteral: "empty",
@@ -170,6 +239,30 @@ export const map: Record> = {
// ^? (string | number)[]
`,
playgroundUrl: "https://tsplay.dev/m0DBxm",
+ applications: [
+ {
+ library: "prisma",
+ breadcrumbs: [
+ {
+ text: "build",
+ href: "https://github.com/prisma/prisma/blob/37adb2dc0f3121d8e96aa2542db07943b4d40477/helpers/compile/build.ts#L170",
+ },
+ {
+ text: "createBuildOptions",
+ href: "https://github.com/prisma/prisma/blob/37adb2dc0f3121d8e96aa2542db07943b4d40477/helpers/compile/build.ts#L71",
+ },
+ {
+ text: "flatten",
+ href: "https://github.com/prisma/prisma/blob/906d265aacae8f08e177d8c807e91513f074f1f2/helpers/blaze/flatten.ts#L19",
+ },
+ {
+ text: "Flatten",
+ href: "https://github.com/prisma/prisma/blob/906d265aacae8f08e177d8c807e91513f074f1f2/helpers/blaze/flatten.ts#L23",
+ },
+ ],
+ githubStars: 40_100,
+ },
+ ],
insights: [
{
Element: (
@@ -190,6 +283,7 @@ export const map: Record> = {
],
},
// TODO: Pop, Push, Shift, Unshift, Flatten, MergeAll
+ // TODO: Mapped Type, e.g. rxjs, combineLatest > ObservableInputTuple
tuple: {
code: `
type InternalFilter<
@@ -208,6 +302,64 @@ export const map: Record> = {
// ^? [string]
`,
playgroundUrl: "https://tsplay.dev/WJPQ5N",
+ applications: [
+ {
+ library: "prisma",
+ breadcrumbs: [
+ {
+ text: "prisma.$transaction",
+ href: "https://github.com/prisma/prisma/blob/94cd9dcede03b25fe1a28ee4fe3a1da117d86cdb/packages/client/scripts/default-index.d.ts#L60-L63",
+ },
+ {
+ text: "Utils.UnwrapTuple",
+ href: "https://github.com/prisma/prisma/blob/8957496bd9b24c3ad49d998d51c3d52912aa90d7/packages/client/src/runtime/core/types/exported/Utils.ts#L50",
+ },
+ ],
+ githubStars: 40_100,
+ },
+ {
+ library: "zod",
+ breadcrumbs: [
+ {
+ text: "Enum.exclude",
+ href: "https://github.com/colinhacks/zod/blob/4e219d6ad9d5e56e20afd7423092f506400a29e4/src/types.ts#L4420-L4425",
+ },
+ {
+ text: "FilterEnum",
+ href: "https://github.com/colinhacks/zod/blob/4e219d6ad9d5e56e20afd7423092f506400a29e4/src/types.ts#L4316-L4322",
+ },
+ ],
+ githubStars: 34_400,
+ },
+ {
+ library: "rxjs",
+ breadcrumbs: [
+ {
+ text: "combineLatestWith",
+ href: "https://github.com/ReactiveX/rxjs/blob/05894120a55e6339a29ee74ec6ae2ee593af5704/packages/rxjs/src/internal/operators/combineLatestWith.ts#L45-L47",
+ },
+ {
+ text: "Cons",
+ href: "https://github.com/ReactiveX/rxjs/blob/05894120a55e6339a29ee74ec6ae2ee593af5704/packages/rxjs/src/internal/types.ts#L277",
+ },
+ ],
+ githubStars: 30_900,
+ },
+ {
+ library: "ts-pattern",
+ breadcrumbs: [
+ {
+ text: "exhaustive",
+ href: "https://github.com/gvergnaud/ts-pattern/blob/58bd6f6e8bebcf4bddfd3dd92b48b28c45f2030c/src/types/Match.ts#L194-L198",
+ },
+ {
+ text: "DeepExcludeAll",
+ href: "https://github.com/gvergnaud/ts-pattern/blob/58bd6f6e8bebcf4bddfd3dd92b48b28c45f2030c/src/types/Match.ts#L234-L238",
+ },
+ ],
+ githubStars: 12_600,
+ },
+ ],
insights: [
{
Element: ,
@@ -264,6 +416,18 @@ export const map: Record> = {
// ^? { TypeScript: boolean; Python: boolean }
`,
playgroundUrl: "https://tsplay.dev/NrZqVN",
+ applications: [
+ {
+ library: "zod",
+ breadcrumbs: [
+ {
+ text: "util.arrayToEnum",
+ href: "https://github.com/colinhacks/zod/blob/d969423266fccee56ef769da6744cc8bacb04550/src/helpers/util.ts#L141-L162",
+ },
+ ],
+ githubStars: 34_400,
+ },
+ ],
insights: [
{
Element: (
@@ -298,6 +462,40 @@ export const map: Record> = {
// ^? 3 | 1 | 2
`,
playgroundUrl: "https://tsplay.dev/wQQ9Yw",
+ applications: [
+ {
+ library: "prisma",
+ breadcrumbs: [
+ {
+ text: "prisma.$transaction",
+ href: "https://github.com/prisma/prisma/blob/94cd9dcede03b25fe1a28ee4fe3a1da117d86cdb/packages/client/scripts/default-index.d.ts#L56-L59",
+ },
+ {
+ text: "ITXClientDenyList",
+ href: "https://github.com/prisma/prisma/blob/94cd9dcede03b25fe1a28ee4fe3a1da117d86cdb/packages/client/src/runtime/core/types/exported/itxClientDenyList.ts#L5",
+ },
+ ],
+ githubStars: 40_100,
+ },
+ {
+ library: "zod",
+ breadcrumbs: [
+ {
+ text: "enum",
+ href: "https://github.com/colinhacks/zod/blob/4e219d6ad9d5e56e20afd7423092f506400a29e4/src/types.ts#L5427",
+ },
+ {
+ text: "createZodEnum",
+ href: "https://github.com/colinhacks/zod/blob/4e219d6ad9d5e56e20afd7423092f506400a29e4/src/types.ts#L4326-L4333",
+ },
+ {
+ text: "ZodEnum",
+ href: "https://github.com/colinhacks/zod/blob/4e219d6ad9d5e56e20afd7423092f506400a29e4/src/types.ts#L4345-L4349",
+ },
+ ],
+ githubStars: 34_400,
+ },
+ ],
insights: [
{
Element: (
@@ -312,6 +510,7 @@ export const map: Record> = {
},
],
},
+ // TODO: Join, e.g. typeorm mongodb typings - https://github.com/typeorm/typeorm/blob/3647b269ccb1f236595bf8ff3adcca5460a0d205/src/driver/mongodb/typings.ts#L4062-L4068
stringLiteral: "empty",
numericLiteral: {
code: `
@@ -320,6 +519,43 @@ export const map: Record> = {
type Length = LengthOf;
// ^? 3
`,
+ playgroundUrl: "https://tsplay.dev/w280rm",
+ applications: [
+ {
+ library: "ts-pattern",
+ breadcrumbs: [
+ {
+ text: "exhaustive",
+ href: "https://github.com/gvergnaud/ts-pattern/blob/58bd6f6e8bebcf4bddfd3dd92b48b28c45f2030c/src/types/Match.ts#L194-L198",
+ },
+ {
+ text: "DeepExcludeAll",
+ href: "https://github.com/gvergnaud/ts-pattern/blob/58bd6f6e8bebcf4bddfd3dd92b48b28c45f2030c/src/types/Match.ts#L234-L238",
+ },
+ {
+ text: "DeepExclude",
+ href: "https://github.com/gvergnaud/ts-pattern/blob/27dbee0cdf35f2ee8350dc763dbaa5d475351c47/src/types/DeepExclude.ts#L3",
+ },
+ {
+ text: "DistributeMatchingUnions",
+ href: "https://github.com/gvergnaud/ts-pattern/blob/8d23bc49b19d9951a61832779c2eeb03d2971fdc/src/types/DistributeUnions.ts#L41-L43",
+ },
+ {
+ text: "FindUnionsMany",
+ href: "https://github.com/gvergnaud/ts-pattern/blob/8d23bc49b19d9951a61832779c2eeb03d2971fdc/src/types/DistributeUnions.ts#L46-L60",
+ },
+ {
+ text: "FindUnions",
+ href: "https://github.com/gvergnaud/ts-pattern/blob/8d23bc49b19d9951a61832779c2eeb03d2971fdc/src/types/DistributeUnions.ts#L80-L84",
+ },
+ {
+ text: "Length",
+ href: "https://github.com/gvergnaud/ts-pattern/blob/e1272af2796979d4b370aee8cc250e978a4c26b6/src/types/helpers.ts#L61",
+ },
+ ],
+ githubStars: 12_600,
+ },
+ ],
insights: [
{
Element: (
@@ -343,7 +579,6 @@ export const map: Record> = {
type: "note",
},
],
- playgroundUrl: "https://tsplay.dev/w280rm",
},
},
object: {
@@ -357,6 +592,26 @@ export const map: Record> = {
// ^^^^^^^^
`,
playgroundUrl: "https://tsplay.dev/mqlPjN",
+ applications: [
+ {
+ library: "rxjs",
+ breadcrumbs: [
+ {
+ text: "race",
+ href: "https://github.com/ReactiveX/rxjs/blob/05894120a55e6339a29ee74ec6ae2ee593af5704/packages/rxjs/src/internal/observable/race.ts#L61",
+ },
+ {
+ text: "raceInit",
+ href: "https://github.com/ReactiveX/rxjs/blob/05894120a55e6339a29ee74ec6ae2ee593af5704/packages/rxjs/src/internal/observable/race.ts#L59",
+ },
+ {
+ text: "subscriptions",
+ href: "https://github.com/ReactiveX/rxjs/blob/05894120a55e6339a29ee74ec6ae2ee593af5704/packages/rxjs/src/internal/observable/race.ts#L61",
+ },
+ ],
+ githubStars: 30_900,
+ },
+ ],
insights: [
{
Element: ,
@@ -427,6 +682,26 @@ export const map: Record> = {
// ^? [['locale', string], ['pageId', string]]
`,
playgroundUrl: "https://tsplay.dev/NdxG6N",
+ applications: [
+ {
+ library: "zod",
+ breadcrumbs: [
+ {
+ text: "object",
+ href: "https://github.com/colinhacks/zod/blob/4e219d6ad9d5e56e20afd7423092f506400a29e4/src/types.ts#L5440",
+ },
+ {
+ text: "ZodObject.keyof",
+ href: "https://github.com/colinhacks/zod/blob/4e219d6ad9d5e56e20afd7423092f506400a29e4/src/types.ts#L3017",
+ },
+ {
+ text: "enumUtil.UnionToTupleString",
+ href: "https://github.com/colinhacks/zod/blob/1d16205a84c90ee2f0903e171e40b53c5da906cf/src/helpers/enumUtil.ts#L18",
+ },
+ ],
+ githubStars: 34_400,
+ },
+ ],
insights: [
{
Element: ,
@@ -488,6 +763,68 @@ export const map: Record> = {
// ^? {getName: () => string} & {setName: (value: string) => void}
`,
playgroundUrl: "https://tsplay.dev/W4Dq7W",
+ applications: [
+ {
+ library: "jest",
+ breadcrumbs: [
+ {
+ text: "jest.mocked",
+ href: "https://github.com/jestjs/jest/blob/9c9ce8ad80c6719c3378dd0058c173830621a3ff/packages/jest-environment/src/index.ts#L223",
+ },
+ {
+ text: "Mocked",
+ href: "https://github.com/jestjs/jest/blob/c5a00aa33a15e040730422af107025e2f23786b6/packages/jest-mock/src/index.ts#L79-L85",
+ },
+ {
+ text: "MockedObject",
+ href: "https://github.com/jestjs/jest/blob/c5a00aa33a15e040730422af107025e2f23786b6/packages/jest-mock/src/index.ts#L61-L69",
+ },
+ ],
+ githubStars: 44_300,
+ },
+ {
+ library: "typeorm",
+ breadcrumbs: [
+ {
+ text: "Repository.create",
+ href: "https://github.com/typeorm/typeorm/blob/99d8249e450f7e649685105b372e265f41a0ee47/src/repository/Repository.ts#L114-L118",
+ },
+ {
+ text: "DeepPartial",
+ href: "https://github.com/typeorm/typeorm/blob/8ba742eb36586a21a918ed178208874a53ace3f9/src/common/DeepPartial.ts#L4-L14",
+ },
+ ],
+ githubStars: 34_600,
+ },
+ {
+ library: "zod",
+ breadcrumbs: [
+ {
+ text: "object",
+ href: "https://github.com/colinhacks/zod/blob/4e219d6ad9d5e56e20afd7423092f506400a29e4/src/types.ts#L5440",
+ },
+ {
+ text: "ZodObject.partial",
+ href: "https://github.com/colinhacks/zod/blob/4e219d6ad9d5e56e20afd7423092f506400a29e4/src/types.ts#L2946-L2950",
+ },
+ ],
+ githubStars: 34_400,
+ },
+ {
+ library: "zod",
+ breadcrumbs: [
+ {
+ text: "object",
+ href: "https://github.com/colinhacks/zod/blob/4e219d6ad9d5e56e20afd7423092f506400a29e4/src/types.ts#L5440",
+ },
+ {
+ text: "ZodObject.required",
+ href: "https://github.com/colinhacks/zod/blob/4e219d6ad9d5e56e20afd7423092f506400a29e4/src/types.ts#L2979-L2983",
+ },
+ ],
+ githubStars: 34_400,
+ },
+ ],
insights: [
{
Element: (
@@ -597,7 +934,8 @@ export const map: Record> = {
},
],
},
- // TODO: add values
+ // TODO: Path
+ // TODO: add values: typeorm ServerType, e.g. (typeof ServerType)[keyof typeof ServerType]
union: {
code: `
type KeysFrom