Skip to content

Commit 6077df2

Browse files
committed
Convert examples to Markdown
1 parent 0daaee9 commit 6077df2

36 files changed

+10682
-1142
lines changed

.storybook/addons.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// import '@storybook/addon-actions/register';
2+
import "@storybook/addon-links/register";

.storybook/config.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from "react";
2+
import { configure } from "@storybook/react";
3+
import { addDecorator } from "@storybook/react";
4+
5+
// automatically import all files ending in *.stories.js
6+
configure(require.context("../stories", true, /\.stories\.tsx$/), module);
7+
8+
const styles = {
9+
fontFamily: "Open Sans, sans-serif",
10+
fontSize: "1rem",
11+
maxWidth: 1000,
12+
paddingLeft: 20,
13+
paddingRight: 20,
14+
margin: "0 auto",
15+
};
16+
const LayoutDecorator = storyFn => <div style={styles}>{storyFn()}</div>;
17+
addDecorator(LayoutDecorator);

.storybook/preview-head.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<link
2+
href="https://fonts.googleapis.com/css?family=Open+Sans:400,600&display=swap"
3+
rel="stylesheet"
4+
/>

.storybook/webpack.config.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const path = require("path");
2+
const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");
3+
const MONACO_DIR = path.resolve(__dirname, "./node_modules/monaco-editor");
4+
const util = require("util");
5+
6+
module.exports = async ({ config }) => {
7+
config.module.rules.push({
8+
test: /\.tsx?$/,
9+
use: ["babel-loader"],
10+
});
11+
config.module.rules.push({
12+
test: /\.css$/,
13+
use: ["style-loader", "css-loader"],
14+
include: MONACO_DIR,
15+
});
16+
config.plugins.push(new MonacoWebpackPlugin());
17+
config.resolve.extensions = [".ts", ".tsx", ".js"];
18+
config.externals = { "@microsoft/typescript-etw": "FakeModule" };
19+
return config;
20+
};

babel.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
presets: ["@babel/env", "@babel/react", "@babel/typescript"],
3+
};

examples/array-element-access.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
This seems wrong...
2+
3+
```tsx
4+
const array = [0, 1];
5+
array[0];
6+
array[1];
7+
array[2]; // hey! this should be an error!
8+
```
9+
10+
but just like objects are mutable in TS, so are arrays.
11+
Imagine this case:
12+
13+
```tsx
14+
const pushToArray = <T extends any>(arr: T[], element: T): T[] => {
15+
arr.push(element);
16+
return arr;
17+
};
18+
19+
const arr = [0, 1];
20+
pushToArray(arr, 2); // now arr[2] exists
21+
arr[2]; // if TS showed an error here, it would be extremely annoying
22+
```
23+
24+
TypeScript would have to do a lot more work to analyze your code to figure
25+
out safe array access - and it's just not a common enough case to be worth
26+
the cost.
27+
28+
However, tuple types exist, which have a known length that can never change.
29+
Checking access on these is cheap, so use `as const` to change from number[]
30+
(array of numbers of any length) to [number, number] (array of numbers with
31+
a length of 2).
32+
(you'll see the term "const context" floating around: it means "immutable")
33+
34+
```tsx
35+
const tuple = [0, 1] as const;
36+
37+
tuple[0];
38+
tuple[1];
39+
tuple[2]; // correctly an error
40+
```

examples/array-element-access.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.
Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
1-
export {};
2-
// diagnostic codes: ts2339, ts2741
1+
diagnostic codes: ts2339, ts2741
32

4-
// possibly related: control flow analysis
5-
// https://github.com/Microsoft/TypeScript/issues/9998
3+
## Related Issues
64

7-
// Sometimes, you need to initialize an object and add properties
8-
// one by one, often with a check each time.
5+
[Issue #9998: Tradeoffs in Control Flow Analysis](https://github.com/Microsoft/TypeScript/issues/9998)
96

7+
## The Problem
8+
9+
Sometimes, you need to initialize an object and add properties one by one, often with a check each time.
10+
11+
```tsx
1012
interface Result {
1113
name?: string;
1214
value: string | number;
1315
}
1416

15-
let buildResult;
16-
buildResult = (name?: string) => {
17+
const startWithEmpty = (name?: string) => {
1718
const result = {};
1819
// error, this property doesn't exist on {}
1920
if (name) {
@@ -22,32 +23,42 @@ buildResult = (name?: string) => {
2223
result.value = 1;
2324
};
2425

25-
buildResult = (name?: string) => {
26+
const addType = (name?: string) => {
2627
const result: Result = {}; // error, missing property "value"
2728
if (name) {
2829
result.name = name;
2930
}
3031
result.value = 1;
3132
};
3233

33-
buildResult = (name?: string): Result => {
34+
const addAssertion = (name?: string): Result => {
3435
const result = {} as Result;
3536
if (name) {
3637
result.name = name;
3738
}
3839
result.value = 1; // comment out this line: note, no error
3940
return result;
4041
};
42+
```
43+
44+
## Why does this happen?
45+
46+
## What do I do about it?
47+
48+
For simple cases, just have two returns.
4149

42-
// for simple cases, just have two returns
50+
```tsx
4351
buildResult = (name?: string): Result => {
4452
if (name) {
4553
return { name, value: 1 };
4654
}
4755
return { value: 1 };
4856
};
57+
```
4958

50-
// ...or redefine a variable
59+
...or redefine a variable.
60+
61+
```tsx
5162
buildResult = (name?: string): Result => {
5263
let result: Result;
5364
if (name) {
@@ -57,36 +68,37 @@ buildResult = (name?: string): Result => {
5768
}
5869
return result;
5970
};
71+
```
72+
73+
...or use a utility.
74+
75+
```tsx
76+
// remember keys + entries and open types:
77+
// https://github.com/Microsoft/TypeScript/pull/12253#issuecomment-263132208
78+
const keys = Object.keys as <T>(o: T) => Extract<keyof T, string>[];
79+
const entries = Object.entries as <
80+
T extends { [key: string]: any },
81+
K extends keyof T
82+
>(
83+
o: T,
84+
) => [keyof T, T[K]][];
6085

61-
// or use a utility
6286
const filterNulls = <T extends { [key: string]: any }, K>(
63-
obj: T
87+
obj: T,
6488
): { [K in keyof T]: T[K] extends any ? T[K] : null } => {
65-
return entries(obj).reduce(
66-
(acc, [key, value]) => {
67-
// == null matches null or undefined
68-
if (value != null) {
69-
acc[key] = value;
70-
}
71-
return acc;
72-
},
73-
{} as T
74-
);
89+
return entries(obj).reduce((acc, [key, value]) => {
90+
// == null matches null or undefined
91+
if (value != null) {
92+
acc[key] = value;
93+
}
94+
return acc;
95+
}, {} as T);
7596
};
7697

7798
buildResult = (name?: string): Result => {
7899
return filterNulls({
79100
name: name,
80-
value: 1
101+
value: 1,
81102
});
82103
};
83-
84-
// remember keys + entries and open types:
85-
// https://github.com/Microsoft/TypeScript/pull/12253#issuecomment-263132208
86-
const keys = Object.keys as <T>(o: T) => (Extract<keyof T, string>)[];
87-
const entries = Object.entries as <
88-
T extends { [key: string]: any },
89-
K extends keyof T
90-
>(
91-
o: T
92-
) => [keyof T, T[K]][];
104+
```

0 commit comments

Comments
 (0)