diff --git a/packages/core/content-types/__tests__/tiptap.test.js b/packages/core/content-types/__tests__/tiptap.test.js index 9bd109804..bd124be50 100644 --- a/packages/core/content-types/__tests__/tiptap.test.js +++ b/packages/core/content-types/__tests__/tiptap.test.js @@ -50,10 +50,10 @@ test("remove attachments with particular hash", async () => { const HTMLS = { tables: `
| Goal | To introduce various features of the app to the user and to convert a user on trial or basic plan to upgrade. |
| Frequency | 1/week or 2/week |
| Types | Feature intro, upgrade promo, one time emails |
Features:
hell
what
sdsdavav | daskvjbdsva | vsadjkvsadbvjk |
|---|---|---|
dsvsajkdb | dskajvbsadj | kjdasvbkj |
daskvbkdsa | kdsajvbsajkd | kjdsavbdsa |
Typescript is one of those languages that appear to be very simple. It's often described as "Javascript with types" and it fits that name very well. However, what many don't realize starting out with Typescript is that Typescript is a language and like all other languages it has it's own "secrets", it's own set of quirks.
When I started out with Typescript a few years back, I absolutely hated it. It was unnecessary, a box of clutter, making me write code that would never actually run. I hated defining interfaces, typing out all my functions, and thinking in terms I was not used to as a Javascript developer. Before Javascript, I had coded in C# and I had never really liked C# (I still don't) mostly for the huge amounts of boilerplate and magic involved. Typescript is heavily inspired by C# and seeing that contaminate the Javascript ecosystem irked me no end.
That was all just fluff. Typescript is a great language solving a considerable amount of problems for a huge amount of developers. And generics is the hidden weapon behind it all.
For all points and purposes, generics shouldn't exist. They are one of the main factors behind abysmal code readability. But in the right hands, generics turn into a super-weapon.
The main problem generics try to solve is how to take in multiple types of parameters. This is a solved problem but requires duplicating your functions or using conditions to separate out different logic for different types. That is essentially what generics do as well but hidden from human eyes.
Think of a container that can take any type of item as long as it is not a circle. In Javascript, this becomes a problem you have to solve at runtime with checks & conditions:
var container = [];\nfunction putIntoContainer(item) {\n if (item.type === "round") throw new Error("Rounded items not supported.")\n container.push(item);\n}\n\nvar square = {type: "square"}\nvar circle = {type: "round"}\nputIntoContainer(square)\nputIntoContainer(circle) // ERROR! Rounded items not supported!\nThere are many ways to solve this problem and some are even practical. The issue here isn't of repetition but of doing unnecessary work. Type safe languages would automatically give an error if there was a wrong type but Javascript knows nothing about the item.
In Typescript, this will be solved much more succinctly:
// first define the types of items we'll handle\n// i.e. we don't want to handle any item other\n// than square or round.\n// This gives us nice auto completion and safety\n// against typos.\ntype ItemTypes = "square" | "round";\n\n// Define a generic item that can be of any type\n// defined in ItemTypes.\n// i.e. Item<"triangle"> will give an error.\ntype Item<TItemType extends ItemTypes> = {\n type?: TItemType;\n width: number;\n height: number;\n};\n\n// This is just syntax sugar to increase readability.\ntype Square = Item<"square">;\ntype Circle = Item<"round">;\n\n// Our container is just a simple wrapper around an array\n// that accepts items of only a specific type.\ntype Container<TItemType extends ItemTypes> = Array<Item<TItemType>>;\n\nvar squareContainer: Container<"square"> = [];\nvar roundContainer: Container<"round"> = [];\n\n// This wrapper is unnecessary, of course, because array.push\n// already does this. Only for demonstration purposes.\nfunction putIntoContainer<\n TItemType extends ItemTypes,\n TItem extends Item<TItemType>\n>(container: Container<TItemType>, item: TItem) {\n container.push(item);\n}\n\nvar square: Square = { width: 100, height: 200 };\nvar circle: Circle = { width: 200, height: 500 };\n\nputIntoContainer(squareContainer, square);\nputIntoContainer(roundContainer, circle);\nputIntoContainer(roundContainer, square); // Error: Argument of type 'Square' is not assignable to parameter of type 'Item<"round">'.\nputIntoContainer(squareContainer, circle); // Error: Argument of type 'Circle' is not assignable to parameter of type 'Item<"square">'.\nA lot more code, I know, and if you don't know how generics work that blob of code is utter nonsense. One of the main reasons I avoided Typescript for a long time. But look at the benefits:
You have 100% compile-time type safety.
You can't put a round item in a square container (you will get compiler error).
You didn't write any extra runtime code.
Expanding on point #3, after transpilation the above code will turn more-or-less into:
var squareContainer = [];\nvar roundContainer = [];\n\nfunction putIntoContainer(container, item) {\n container.push(item);\n}\n\nvar square = { width: 100, height: 200 };\nvar circle = { width: 200, height: 500 };\n\nputIntoContainer(squareContainer, square);\nputIntoContainer(roundContainer, circle);\nThis is the power of generics. More specifically, this is Typescript generics at a glance.
But this post was supposed to be about the "Secrets" of Typescript Generics, right? Well, let's get into that.
hell
what
sdsdavav | daskvjbdsva | vsadjkvsadbvjk |
|---|---|---|
dsvsajkdb | dskajvbsadj | kjdasvbkj |
daskvbkdsa | kdsajvbsajkd | kjdsavbdsa |
Typescript is one of those languages that appear to be very simple. It's often described as "Javascript with types" and it fits that name very well. However, what many don't realize starting out with Typescript is that Typescript is a language and like all other languages it has it's own "secrets", it's own set of quirks.
When I started out with Typescript a few years back, I absolutely hated it. It was unnecessary, a box of clutter, making me write code that would never actually run. I hated defining interfaces, typing out all my functions, and thinking in terms I was not used to as a Javascript developer. Before Javascript, I had coded in C# and I had never really liked C# (I still don't) mostly for the huge amounts of boilerplate and magic involved. Typescript is heavily inspired by C# and seeing that contaminate the Javascript ecosystem irked me no end.
That was all just fluff. Typescript is a great language solving a considerable amount of problems for a huge amount of developers. And generics is the hidden weapon behind it all.
For all points and purposes, generics shouldn't exist. They are one of the main factors behind abysmal code readability. But in the right hands, generics turn into a super-weapon.
The main problem generics try to solve is how to take in multiple types of parameters. This is a solved problem but requires duplicating your functions or using conditions to separate out different logic for different types. That is essentially what generics do as well but hidden from human eyes.
Think of a container that can take any type of item as long as it is not a circle. In Javascript, this becomes a problem you have to solve at runtime with checks & conditions:
var container = [];\nfunction putIntoContainer(item) {\n if (item.type === "round") throw new Error("Rounded items not supported.")\n container.push(item);\n}\n\nvar square = {type: "square"}\nvar circle = {type: "round"}\nputIntoContainer(square)\nputIntoContainer(circle) // ERROR! Rounded items not supported!\nThere are many ways to solve this problem and some are even practical. The issue here isn't of repetition but of doing unnecessary work. Type safe languages would automatically give an error if there was a wrong type but Javascript knows nothing about the item.
In Typescript, this will be solved much more succinctly:
// first define the types of items we'll handle\n// i.e. we don't want to handle any item other\n// than square or round.\n// This gives us nice auto completion and safety\n// against typos.\ntype ItemTypes = "square" | "round";\n\n// Define a generic item that can be of any type\n// defined in ItemTypes.\n// i.e. Item<"triangle"> will give an error.\ntype Item<TItemType extends ItemTypes> = {\n type?: TItemType;\n width: number;\n height: number;\n};\n\n// This is just syntax sugar to increase readability.\ntype Square = Item<"square">;\ntype Circle = Item<"round">;\n\n// Our container is just a simple wrapper around an array\n// that accepts items of only a specific type.\ntype Container<TItemType extends ItemTypes> = Array<Item<TItemType>>;\n\nvar squareContainer: Container<"square"> = [];\nvar roundContainer: Container<"round"> = [];\n\n// This wrapper is unnecessary, of course, because array.push\n// already does this. Only for demonstration purposes.\nfunction putIntoContainer<\n TItemType extends ItemTypes,\n TItem extends Item<TItemType>\n>(container: Container<TItemType>, item: TItem) {\n container.push(item);\n}\n\nvar square: Square = { width: 100, height: 200 };\nvar circle: Circle = { width: 200, height: 500 };\n\nputIntoContainer(squareContainer, square);\nputIntoContainer(roundContainer, circle);\nputIntoContainer(roundContainer, square); // Error: Argument of type 'Square' is not assignable to parameter of type 'Item<"round">'.\nputIntoContainer(squareContainer, circle); // Error: Argument of type 'Circle' is not assignable to parameter of type 'Item<"square">'.\nA lot more code, I know, and if you don't know how generics work that blob of code is utter nonsense. One of the main reasons I avoided Typescript for a long time. But look at the benefits:
You have 100% compile-time type safety.
You can't put a round item in a square container (you will get compiler error).
You didn't write any extra runtime code.
Expanding on point #3, after transpilation the above code will turn more-or-less into:
var squareContainer = [];\nvar roundContainer = [];\n\nfunction putIntoContainer(container, item) {\n container.push(item);\n}\n\nvar square = { width: 100, height: 200 };\nvar circle = { width: 200, height: 500 };\n\nputIntoContainer(squareContainer, square);\nputIntoContainer(roundContainer, circle);\nThis is the power of generics. More specifically, this is Typescript generics at a glance.
But this post was supposed to be about the "Secrets" of Typescript Generics, right? Well, let's get into that.
Hello
Task item 1
Task item 2
Task item 3
Task item 4
Sub task item 1
Sub task item 2
Task Item 5
Nene
dasvsadv
adsva\`sd
vasd
vsadvdsa
Testing outline list:
My outline list
works
but sometimes
It doesn't
what do I do?
I need to do something!
Makes no sense!
Yes it doesn't!
Testing outline list:
My outline list
works
but sometimes
It doesn't
what do I do?
I need to do something!
Makes no sense!
Yes it doesn't!
hello` };