Skip to content

Commit 9d6c5b5

Browse files
committed
General handbook faffing
1 parent 1f8090e commit 9d6c5b5

File tree

15 files changed

+440
-502
lines changed

15 files changed

+440
-502
lines changed

packages/documentation/copy/en/handbook-v2/More on Functions.md

+56-2
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ function myForEach(arr: any[], callback: (arg: any, index?: number) => void) {
378378
}
379379
```
380380

381-
What people usually _intend_ when writing `index?` as an optional parameter is that they want both of these calls to be legal:
381+
What people usually intend when writing `index?` as an optional parameter is that they want both of these calls to be legal:
382382

383383
```ts twoslash
384384
// @errors: 2532
@@ -538,6 +538,58 @@ Callers can invoke this with either sort of value, and as an added bonus, we don
538538

539539
> Always prefer parameters with union types instead of overloads when possible
540540
541+
### Declaring `this` in a Function
542+
543+
TypeScript will infer what the `this` function should be in a function via code flow analysis, for example in the following:
544+
545+
```ts twoslash
546+
const user = {
547+
id: 123,
548+
549+
admin: false,
550+
becomeAdmin: function () {
551+
this.admin = true;
552+
},
553+
};
554+
```
555+
556+
TypeScript understands that the function `user.becomeAdmin` has a corresponding `this` which is the outer object `user`. `this`, _heh_, can be enough for a lot of cases, but there are a lot of cases where you need more control over what object `this` represents. The JavaScript specification states that you cannot have a parameter called `this`, and so TypeScript uses that syntax space to let you declare the type for `this` in the function body.
557+
558+
```ts twoslash
559+
interface User {
560+
id: number;
561+
isAdmin: boolean;
562+
}
563+
declare const getDB: () => DB;
564+
// ---cut---
565+
interface DB {
566+
filterUsers(filter: (this: User) => boolean): User[];
567+
}
568+
569+
const db = getDB();
570+
const admins = db.filterUsers(function () {
571+
return this.isAdmin;
572+
});
573+
```
574+
575+
This pattern is common with callback-style APIs, where another object typically controls when your function is called. Note that you need to use `function` and not arrow functions to get this behavior:
576+
577+
```ts twoslash
578+
// @errors: 7041 7017
579+
interface User {
580+
id: number;
581+
isAdmin: boolean;
582+
}
583+
declare const getDB: () => DB;
584+
interface DB {
585+
filterUsers(filter: (this: User) => boolean): User[];
586+
}
587+
588+
// ---cut---
589+
const db = getDB();
590+
const admins = db.filterUsers(() => this.isAdmin);
591+
```
592+
541593
## Other Types to Know About
542594

543595
There are some additional types you'll want to recognize that appear often when working with function types.
@@ -681,7 +733,7 @@ This can lead to some surprising behavior:
681733
```ts twoslash
682734
// @errors: 2556
683735
// Inferred type is number[] -- "an array with zero or more numbers",
684-
// not specfically two numbers
736+
// not specifically two numbers
685737
const args = [8, 5];
686738
const angle = Math.atan2(...args);
687739
```
@@ -695,6 +747,8 @@ const args = [8, 5] as const;
695747
const angle = Math.atan2(...args);
696748
```
697749

750+
Using rest arguments may require turning on [`downlevelIteration`](/tsconfig/#downlevelIteration) when targeting older runtimes.
751+
698752
<!-- TODO link to downlevel iteration -->
699753

700754
## Parameter Destructuring

packages/documentation/copy/en/handbook-v2/Object Types.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -873,7 +873,7 @@ distanceFromOrigin(point);
873873
Here, `distanceFromOrigin` never modifies its elements, but expects a mutable tuple.
874874
Since `point`'s type was inferred as `readonly [3, 4]`, it won't be compatible with `[number, number]` since that type can't guarantee `point`'s elements won't be mutated.
875875

876-
## Other Kinds of Object Members
876+
<!-- ## Other Kinds of Object Members
877877
878878
Most of the declarations in object types:
879879
@@ -883,4 +883,4 @@ Most of the declarations in object types:
883883
884884
### Construct Signatures
885885
886-
### Index Signatures
886+
### Index Signatures -->

packages/shiki-twoslash/src/index.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -60,30 +60,30 @@ export const renderCodeToHTML = (
6060

6161
// Shiki does know the lang, so tokenize
6262
const renderHighlighter = highlighter || storedHighlighter
63+
const metaInfo = info && typeof info === "string" ? info : info.join(" ")
64+
const codefenceMeta = parseCodeFenceInfo(lang, metaInfo || "")
6365

6466
let tokens: IThemedToken[][]
6567
try {
6668
// Shiki does know the lang, so tokenize
6769
tokens = renderHighlighter.codeToThemedTokens(code, lang as any)
6870
} catch (error) {
6971
// Shiki doesn't know this lang
70-
return plainTextRenderer(code, shikiOptions || {})
72+
return plainTextRenderer(code, shikiOptions || {}, codefenceMeta.meta)
7173
}
7274

7375
// Twoslash specific renderer
7476
if (info.includes("twoslash") && twoslash) {
75-
const metaInfo = info && typeof info === "string" ? info : info.join(" ")
76-
const codefenceMeta = parseCodeFenceInfo(lang, metaInfo || "")
7777
return twoslashRenderer(tokens, shikiOptions || {}, twoslash, codefenceMeta.meta)
7878
}
7979

8080
// TSConfig renderer
8181
if (lang && lang.startsWith("json") && info.includes("tsconfig")) {
82-
return tsconfigJSONRenderer(tokens, shikiOptions || {})
82+
return tsconfigJSONRenderer(tokens, shikiOptions || {}, codefenceMeta.meta)
8383
}
8484

8585
// Otherwise just the normal shiki renderer
86-
return defaultShikiRenderer(tokens, { langId: lang })
86+
return defaultShikiRenderer(tokens, { langId: lang }, codefenceMeta.meta)
8787
}
8888

8989
/**

packages/shiki-twoslash/src/renderers/plain.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ export interface HtmlRendererOptions {
88
}
99

1010
/** You don't have a language which shiki twoslash can handle, make a DOM compatible version */
11-
export function plainTextRenderer(code: string, options: HtmlRendererOptions) {
11+
export function plainTextRenderer(code: string, options: HtmlRendererOptions, codefenceMeta: any) {
1212
let html = ""
1313
const bg = options.bg || "#fff"
1414
const fg = options.fg || "black"
15+
const classes = (codefenceMeta && codefenceMeta.class) || ""
1516

16-
html += `<pre class="shiki" style="background-color: ${bg}; color: ${fg}">`
17+
html += `<pre class="shiki ${classes}" style="background-color: ${bg}; color: ${fg}">`
1718
if (options.langId) {
1819
html += `<div class="language-id">${options.langId}</div>`
1920
}

packages/shiki-twoslash/src/renderers/shiki.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ import { HtmlRendererOptions } from "./plain"
33

44
type Lines = import("shiki").IThemedToken[][]
55

6-
export function defaultShikiRenderer(lines: Lines, options: HtmlRendererOptions) {
6+
export function defaultShikiRenderer(lines: Lines, options: HtmlRendererOptions, codefenceMeta: any) {
77
let html = ""
88

99
const bg = options.bg || "#fff"
1010
const fg = options.fg || "black"
11+
const classes = (codefenceMeta && codefenceMeta.class) || ""
1112

12-
html += `<pre class="shiki" style="background-color: ${bg}; color: ${fg}">`
13+
html += `<pre class="shiki ${classes}" style="background-color: ${bg}; color: ${fg}">`
1314
if (options.langId) {
1415
html += `<div class="language-id">${options.langId}</div>`
1516
}

packages/shiki-twoslash/src/renderers/tsconfig.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@ const isKeyInTSConfig = (token: IThemedToken) => {
2323
* @param lines the result of shiki highlighting
2424
* @param options shiki display options
2525
*/
26-
export function tsconfigJSONRenderer(lines: Lines, options: HtmlRendererOptions) {
26+
export function tsconfigJSONRenderer(lines: Lines, options: HtmlRendererOptions, codefenceMeta: any) {
2727
let html = ""
2828

2929
const bg = options.bg || "#fff"
3030
const fg = options.fg || "black"
31+
const classes = codefenceMeta.class || ""
3132

32-
html += `<pre class="shiki tsconfig lsp" style="background-color: ${bg}; color: ${fg}">`
33+
html += `<pre class="shiki tsconfig lsp ${classes}" style="background-color: ${bg}; color: ${fg}">`
3334
if (options.langId) {
3435
html += `<div class="language-id">${options.langId}</div>`
3536
}

packages/shiki-twoslash/src/renderers/twoslash.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ export function twoslashRenderer(lines: Lines, options: HtmlRendererOptions, two
2929
const hl = shouldHighlightLine(codefenceMeta)
3030
const bg = options.bg || "#fff"
3131
const fg = options.fg || "black"
32+
const classes = codefenceMeta.class || ""
3233

33-
html += `<pre class="shiki twoslash lsp" style="background-color: ${bg}; color: ${fg}">`
34+
html += `<pre class="shiki twoslash lsp ${classes}" style="background-color: ${bg}; color: ${fg}">`
3435
if (options.langId) {
3536
html += `<div class="language-id">${options.langId}</div>`
3637
}

packages/shiki-twoslash/test/tsconfig-renderer.test.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ describe("with a simple example", () => {
1414
}
1515
`
1616
const tokens = highlighter.codeToThemedTokens(code, "json")
17-
const html = renderers.tsconfigJSONRenderer(tokens, {})
17+
const html = renderers.tsconfigJSONRenderer(tokens, {}, {})
1818

1919
expect(html).toMatchInlineSnapshot(
20-
`"<pre class=\\"shiki tsconfig lsp\\" style=\\"background-color: #fff; color: black\\"><div class='code-container'><code><div class='line'></div><div class='line'><span style=\\"color: #D4D4D4\\">{</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #9CDCFE\\">\\"<a aria-hidden=true href='https://www.typescriptlang.org/tsconfig#compilerOptions'><data-lsp lsp=\\"The set of compiler options for your project\\">compilerOptions</data-lsp></a>\\"</span><span style=\\"color: #D4D4D4\\">: {</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #9CDCFE\\">\\"<a aria-hidden=true href='https://www.typescriptlang.org/tsconfig#module'><data-lsp lsp=\\"Specify what module code is generated.\\">module</data-lsp></a>\\"</span><span style=\\"color: #D4D4D4\\">: </span><span style=\\"color: #CE9178\\">\\"commonjs\\"</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> },</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #9CDCFE\\">\\"<a aria-hidden=true href='https://www.typescriptlang.org/tsconfig#files'><data-lsp lsp=\\"Include a list of files. This does not support glob patterns, as opposed to \`include\`.\\">files</data-lsp></a>\\"</span><span style=\\"color: #D4D4D4\\">: [</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #CE9178\\">\\"core.ts\\"</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> ]</span></div><div class='line'><span style=\\"color: #D4D4D4\\">}</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span></div></code></div></pre>"`
20+
`"<pre class=\\"shiki tsconfig lsp \\" style=\\"background-color: #fff; color: black\\"><div class='code-container'><code><div class='line'></div><div class='line'><span style=\\"color: #D4D4D4\\">{</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #9CDCFE\\">\\"<a aria-hidden=true href='https://www.typescriptlang.org/tsconfig#compilerOptions'><data-lsp lsp=\\"The set of compiler options for your project\\">compilerOptions</data-lsp></a>\\"</span><span style=\\"color: #D4D4D4\\">: {</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #9CDCFE\\">\\"<a aria-hidden=true href='https://www.typescriptlang.org/tsconfig#module'><data-lsp lsp=\\"Specify what module code is generated.\\">module</data-lsp></a>\\"</span><span style=\\"color: #D4D4D4\\">: </span><span style=\\"color: #CE9178\\">\\"commonjs\\"</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> },</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #9CDCFE\\">\\"<a aria-hidden=true href='https://www.typescriptlang.org/tsconfig#files'><data-lsp lsp=\\"Include a list of files. This does not support glob patterns, as opposed to \`include\`.\\">files</data-lsp></a>\\"</span><span style=\\"color: #D4D4D4\\">: [</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #CE9178\\">\\"core.ts\\"</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> ]</span></div><div class='line'><span style=\\"color: #D4D4D4\\">}</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span></div></code></div></pre>"`
2121
)
2222
})
2323
})
@@ -33,7 +33,7 @@ describe("with a simple example", () => {
3333
}
3434
`
3535
const tokens = highlighter.codeToThemedTokens(code, "json")
36-
const html = renderers.tsconfigJSONRenderer(tokens, {})
36+
const html = renderers.tsconfigJSONRenderer(tokens, {}, {})
3737

3838
expect(html.includes("https://www.typescriptlang.org/tsconfig#jsx")).toBeTruthy()
3939
})
@@ -48,7 +48,7 @@ describe("with a simple example", () => {
4848
}
4949
`
5050
const tokens = highlighter.codeToThemedTokens(code, "json")
51-
const html = renderers.tsconfigJSONRenderer(tokens, {})
51+
const html = renderers.tsconfigJSONRenderer(tokens, {}, {})
5252

5353
expect(html.includes("<data-lsp")).toBeTruthy()
5454
})

packages/shiki-twoslash/test/twoslash-renderer.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ it("handles multi-line queries with comments", async () => {
139139
const html = renderCodeToHTML(twoslash.code, "ts", ["twoslash"], {}, highlighter, twoslash)
140140

141141
expect(html).toMatchInlineSnapshot(`
142-
"<pre class=\\"shiki twoslash lsp\\" style=\\"background-color: #fff; color: black\\"><div class='code-container'><code><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #569CD6\\">function</span><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #DCDCAA\\"><data-lsp lsp='function f(): {&amp;#13; x: number;&amp;#13; y: number;&amp;#13;}'>f</data-lsp></span><span style=\\"color: #D4D4D4\\">() {</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #C586C0\\">return</span><span style=\\"color: #D4D4D4\\"> { </span><span style=\\"color: #9CDCFE\\"><data-lsp lsp='(property) x: number'>x</data-lsp>:</span><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #B5CEA8\\">10</span><span style=\\"color: #D4D4D4\\">, </span><span style=\\"color: #9CDCFE\\"><data-lsp lsp='(property) y: number'>y</data-lsp>:</span><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #B5CEA8\\">3</span><span style=\\"color: #D4D4D4\\"> };</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> }</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #569CD6\\">type</span><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #4EC9B0\\"><data-lsp lsp='type P = {&amp;#13; x: number;&amp;#13; y: number;&amp;#13;}'>P</data-lsp></span><span style=\\"color: #D4D4D4\\"> = </span><span style=\\"color: #4EC9B0\\"><data-lsp lsp='type ReturnType&amp;lt;T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any'>ReturnType</data-lsp></span><span style=\\"color: #D4D4D4\\">&lt;</span><span style=\\"color: #569CD6\\">typeof</span><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #9CDCFE\\"><data-lsp lsp='function f(): {&amp;#13; x: number;&amp;#13; y: number;&amp;#13;}'>f</data-lsp></span><span style=\\"color: #D4D4D4\\">&gt;;</span></div><span class='query'> // ^ = type P = {
142+
"<pre class=\\"shiki twoslash lsp \\" style=\\"background-color: #fff; color: black\\"><div class='code-container'><code><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #569CD6\\">function</span><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #DCDCAA\\"><data-lsp lsp='function f(): {&amp;#13; x: number;&amp;#13; y: number;&amp;#13;}'>f</data-lsp></span><span style=\\"color: #D4D4D4\\">() {</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #C586C0\\">return</span><span style=\\"color: #D4D4D4\\"> { </span><span style=\\"color: #9CDCFE\\"><data-lsp lsp='(property) x: number'>x</data-lsp>:</span><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #B5CEA8\\">10</span><span style=\\"color: #D4D4D4\\">, </span><span style=\\"color: #9CDCFE\\"><data-lsp lsp='(property) y: number'>y</data-lsp>:</span><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #B5CEA8\\">3</span><span style=\\"color: #D4D4D4\\"> };</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> }</span></div><div class='line'><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #569CD6\\">type</span><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #4EC9B0\\"><data-lsp lsp='type P = {&amp;#13; x: number;&amp;#13; y: number;&amp;#13;}'>P</data-lsp></span><span style=\\"color: #D4D4D4\\"> = </span><span style=\\"color: #4EC9B0\\"><data-lsp lsp='type ReturnType&amp;lt;T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any'>ReturnType</data-lsp></span><span style=\\"color: #D4D4D4\\">&lt;</span><span style=\\"color: #569CD6\\">typeof</span><span style=\\"color: #D4D4D4\\"> </span><span style=\\"color: #9CDCFE\\"><data-lsp lsp='function f(): {&amp;#13; x: number;&amp;#13; y: number;&amp;#13;}'>f</data-lsp></span><span style=\\"color: #D4D4D4\\">&gt;;</span></div><span class='query'> // ^ = type P = {
143143
// x: number;
144144
// y: number;
145145
// }</span></code><a href='https://www.typescriptlang.org/play/#code/FAAhDMFcDsGMBcCWB7aEAUBKEBvUYQAnAU3kkLRxAA8AuEARgAYAaEAT3oGYQBfAbny988dgAdiIAAogAvCABKpctAAq44gB5RE5OAgA+QWAD0JggD0A-MCA'>Try</a></div></pre>"

0 commit comments

Comments
 (0)