1
- # A typed querySelector function for Flow
1
+ # A typed querySelector function
2
+
3
+ Query the document tree by selector, filtering by element type.
2
4
3
5
## Installation
4
6
@@ -8,27 +10,95 @@ $ npm install @github/query-selector
8
10
9
11
## Usage
10
12
13
+ This library provides a set of functions to query the document tree with a
14
+ standard selector paired with an additional type filter applied to the result.
15
+
16
+ An element must match the selector as well as the type for it to be returned.
17
+
18
+ - ` query(context, selector, klass) `
19
+ - ` querySelectorAll(context, selector, klass) `
20
+ - ` closest(element, selector, klass) `
21
+ - ` namedItem(element, name, klass) `
22
+ - ` getAttribute(element, name) `
23
+
11
24
``` js
12
25
import {closest , getAttribute , query , querySelectorAll } from ' @github/query-selector'
13
26
14
- // Find an element by selector and type or throw if not found.
27
+ // Find an element by selector and type, or throw if not found.
15
28
const image: HTMLImageElement = query (document , ' .avatar' , HTMLImageElement )
16
29
image .src = ' /hubot.png'
17
30
18
- // Find the parent by selector and type or throw if not found.
31
+ // Find the parent by selector and type, or throw if not found.
19
32
const parent: HTMLDetailsElement = closest (image, ' .container' , HTMLDetailsElement)
20
33
parent .open = true
21
34
22
- // Retrieve the attribute's value or throw.
23
- const url: string = getAttribute (image, ' data-url' )
24
-
25
35
// Filter all children by selector and type.
26
36
const inputs: Array <HTMLInputElement > = querySelectorAll (document , ' input' , HTMLInputElement )
27
37
for (const input of inputs) {
28
38
input .value = ' '
29
39
}
40
+
41
+ // Retrieve the attribute's value or throw.
42
+ const url: string = getAttribute (image, ' data-url' )
43
+ ```
44
+
45
+ ## Motivation
46
+
47
+ Finding an individual element in the document tree and operating on it can
48
+ lead to null pointer exceptions.
49
+
50
+ ``` js
51
+ const el = document .querySelector (' .expected-element' )
52
+ // el may be null!
53
+ el .classList .add (' selected' )
54
+ el .setAttribute (' title' , ' hello' )
55
+ ```
56
+
57
+ A safer alternative is to guard against null values with a conditional statement.
58
+
59
+ ``` js
60
+ const el = document .querySelector (' .expected-element' )
61
+ if (el) {
62
+ el .classList .add (' selected' )
63
+ el .setAttribute (' title' , ' hello' )
64
+ }
30
65
```
31
66
67
+ Even if found, the element may be of the wrong type.
68
+
69
+ ``` js
70
+ const el = document .querySelector (' .expected-element' )
71
+ if (el) {
72
+ // Element might not have a value property!
73
+ el .value = ' hello'
74
+ }
75
+ ```
76
+
77
+ Adding an ` instanceof ` test would verify the element has the properties and
78
+ methods we expect.
79
+
80
+ ``` js
81
+ const el = document .querySelector (' .expected-element' )
82
+ if (el instanceof HTMLInputElement ) {
83
+ el .value = ' hello'
84
+ }
85
+ ```
86
+
87
+ Because ` document.querySelector ` is so frequently used in web applications,
88
+ and it's tedious to guard every element query with null checks, these tests
89
+ are most often omitted.
90
+
91
+ When using [ Flow] [ ] , however, these tests become required to pass the
92
+ type checker.
93
+
94
+ The combination of null tests and subclass type refinements feels like we're
95
+ working against the type system, rather than with it, which is the motivation
96
+ for this library.
97
+
98
+ These typed query functions consider a missing element, or an element of the
99
+ wrong type, to be failed assertions and throw an exception to fail as early
100
+ as possible.
101
+
32
102
## Development
33
103
34
104
```
0 commit comments