or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdasync.mdcollections.mdindex.mdnumbers.mdobjects.mdprimitives.mdstrings.mdtyped-arrays.mdvalidation.mdweb-apis.md

web-apis.mddocs/

0

# Web APIs and DOM

1

2

Type checking for web-specific APIs including DOM elements, form data, URL objects, and browser-specific types.

3

4

## Capabilities

5

6

### HTML Element Checking

7

8

Check if a value is an HTML DOM element.

9

10

```typescript { .api }

11

/**

12

* Check if value is an HTML element

13

* @param value - Value to check

14

* @returns True if value is HTMLElement

15

*/

16

function isHtmlElement(value: unknown): value is HTMLElement;

17

```

18

19

**Usage Examples:**

20

21

```typescript

22

import is from '@sindresorhus/is';

23

24

// DOM elements

25

const div = document.createElement('div');

26

const button = document.querySelector('button');

27

const body = document.body;

28

29

is.htmlElement(div); // => true

30

is.htmlElement(button); // => true (if found)

31

is.htmlElement(body); // => true

32

33

// Non-elements

34

is.htmlElement(document); // => false

35

is.htmlElement(window); // => false

36

is.htmlElement('div'); // => false

37

38

// Type guard usage

39

function attachEventListener(element: unknown, event: string, handler: Function) {

40

if (is.htmlElement(element)) {

41

// element is now typed as HTMLElement

42

element.addEventListener(event, handler as EventListener);

43

return () => element.removeEventListener(event, handler as EventListener);

44

}

45

throw new Error('Element must be an HTMLElement');

46

}

47

48

// DOM manipulation

49

function setElementContent(element: unknown, content: string) {

50

if (is.htmlElement(element)) {

51

element.textContent = content;

52

element.style.display = 'block';

53

}

54

}

55

```

56

57

### Blob Type Checking

58

59

Check if a value is a Blob object.

60

61

```typescript { .api }

62

/**

63

* Check if value is a Blob

64

* @param value - Value to check

65

* @returns True if value is Blob

66

*/

67

function isBlob(value: unknown): value is Blob;

68

```

69

70

**Usage Examples:**

71

72

```typescript

73

import is from '@sindresorhus/is';

74

75

// Creating blobs

76

const textBlob = new Blob(['Hello, World!'], { type: 'text/plain' });

77

const jsonBlob = new Blob([JSON.stringify({data: 'test'})], { type: 'application/json' });

78

79

is.blob(textBlob); // => true

80

is.blob(jsonBlob); // => true

81

82

// File objects (inherit from Blob)

83

const fileInput = document.querySelector('input[type="file"]') as HTMLInputElement;

84

const file = fileInput?.files?.[0];

85

if (file) {

86

is.blob(file); // => true (File extends Blob)

87

}

88

89

// Type guard usage

90

async function processBlob(data: unknown) {

91

if (is.blob(data)) {

92

// data is now typed as Blob

93

console.log('Blob size:', data.size);

94

console.log('Blob type:', data.type);

95

96

const text = await data.text();

97

console.log('Blob content:', text);

98

}

99

}

100

101

// File upload handling

102

function handleFileUpload(file: unknown) {

103

if (is.blob(file)) {

104

const formData = new FormData();

105

formData.append('file', file);

106

return formData;

107

}

108

throw new Error('Invalid file provided');

109

}

110

```

111

112

### FormData Type Checking

113

114

Check if a value is a FormData object.

115

116

```typescript { .api }

117

/**

118

* Check if value is FormData

119

* @param value - Value to check

120

* @returns True if value is FormData

121

*/

122

function isFormData(value: unknown): value is FormData;

123

```

124

125

**Usage Examples:**

126

127

```typescript

128

import is from '@sindresorhus/is';

129

130

const formData = new FormData();

131

formData.append('name', 'John');

132

formData.append('age', '30');

133

134

is.formData(formData); // => true

135

is.formData({}); // => false

136

is.formData(new URLSearchParams()); // => false

137

138

// Type guard usage

139

function submitForm(data: unknown) {

140

if (is.formData(data)) {

141

// data is now typed as FormData

142

for (const [key, value] of data.entries()) {

143

console.log(`${key}: ${value}`);

144

}

145

146

return fetch('/api/submit', {

147

method: 'POST',

148

body: data

149

});

150

}

151

throw new Error('Data must be FormData');

152

}

153

154

// Form processing

155

function processFormSubmission(form: HTMLFormElement, additionalData: Record<string, string>) {

156

const formData = new FormData(form);

157

158

// Add additional data

159

Object.entries(additionalData).forEach(([key, value]) => {

160

formData.append(key, value);

161

});

162

163

if (is.formData(formData)) {

164

return submitForm(formData);

165

}

166

}

167

```

168

169

### URL Instance Checking

170

171

Check if a value is a URL object instance.

172

173

```typescript { .api }

174

/**

175

* Check if value is a URL instance

176

* @param value - Value to check

177

* @returns True if value is URL instance

178

*/

179

function isUrlInstance(value: unknown): value is URL;

180

```

181

182

**Usage Examples:**

183

184

```typescript

185

import is from '@sindresorhus/is';

186

187

const url = new URL('https://example.com/path?query=value');

188

const invalidUrl = 'https://example.com';

189

190

is.urlInstance(url); // => true

191

is.urlInstance(invalidUrl); // => false (string, not URL instance)

192

193

// Type guard usage

194

function processUrl(url: unknown) {

195

if (is.urlInstance(url)) {

196

// url is now typed as URL

197

console.log('Protocol:', url.protocol);

198

console.log('Host:', url.host);

199

console.log('Pathname:', url.pathname);

200

console.log('Search params:', url.searchParams.toString());

201

202

return {

203

protocol: url.protocol,

204

host: url.host,

205

path: url.pathname,

206

query: Object.fromEntries(url.searchParams)

207

};

208

}

209

throw new Error('Invalid URL instance');

210

}

211

212

// URL manipulation

213

function addQueryParams(url: unknown, params: Record<string, string>) {

214

if (is.urlInstance(url)) {

215

Object.entries(params).forEach(([key, value]) => {

216

url.searchParams.set(key, value);

217

});

218

return url.toString();

219

}

220

throw new Error('URL must be a URL instance');

221

}

222

```

223

224

### URLSearchParams Type Checking

225

226

Check if a value is a URLSearchParams object.

227

228

```typescript { .api }

229

/**

230

* Check if value is URLSearchParams

231

* @param value - Value to check

232

* @returns True if value is URLSearchParams

233

*/

234

function isUrlSearchParams(value: unknown): value is URLSearchParams;

235

```

236

237

**Usage Examples:**

238

239

```typescript

240

import is from '@sindresorhus/is';

241

242

const params = new URLSearchParams('?name=John&age=30');

243

const paramsFromObject = new URLSearchParams({ city: 'NYC', country: 'US' });

244

245

is.urlSearchParams(params); // => true

246

is.urlSearchParams(paramsFromObject); // => true

247

is.urlSearchParams('?name=John&age=30'); // => false (string)

248

249

// Type guard usage

250

function processSearchParams(params: unknown) {

251

if (is.urlSearchParams(params)) {

252

// params is now typed as URLSearchParams

253

const result: Record<string, string> = {};

254

255

for (const [key, value] of params.entries()) {

256

result[key] = value;

257

}

258

259

return result;

260

}

261

throw new Error('Invalid URLSearchParams');

262

}

263

264

// Query string manipulation

265

function buildQueryString(params: unknown, additionalParams: Record<string, string>) {

266

let searchParams: URLSearchParams;

267

268

if (is.urlSearchParams(params)) {

269

searchParams = new URLSearchParams(params);

270

} else {

271

searchParams = new URLSearchParams();

272

}

273

274

Object.entries(additionalParams).forEach(([key, value]) => {

275

searchParams.set(key, value);

276

});

277

278

return searchParams.toString();

279

}

280

```

281

282

## Usage Patterns

283

284

### DOM Event Handling

285

286

```typescript

287

import is from '@sindresorhus/is';

288

289

function setupEventDelegation(container: unknown, selector: string, handler: Function) {

290

if (!is.htmlElement(container)) {

291

throw new Error('Container must be an HTML element');

292

}

293

294

container.addEventListener('click', (event) => {

295

const target = event.target;

296

297

if (is.htmlElement(target) && target.matches(selector)) {

298

handler(event, target);

299

}

300

});

301

}

302

303

// Usage

304

setupEventDelegation(document.body, '.button', (event, button) => {

305

console.log('Button clicked:', button.textContent);

306

});

307

```

308

309

### File Upload Processing

310

311

```typescript

312

import is from '@sindresorhus/is';

313

314

async function handleFileUpload(file: unknown): Promise<FormData> {

315

if (!is.blob(file)) {

316

throw new Error('File must be a Blob or File');

317

}

318

319

// Validate file size (10MB limit)

320

if (file.size > 10 * 1024 * 1024) {

321

throw new Error('File too large (max 10MB)');

322

}

323

324

// Validate file type

325

if (!file.type.startsWith('image/')) {

326

throw new Error('Only image files are allowed');

327

}

328

329

const formData = new FormData();

330

formData.append('file', file);

331

formData.append('timestamp', Date.now().toString());

332

333

return formData;

334

}

335

336

// Drag and drop handling

337

function setupDropZone(element: unknown) {

338

if (!is.htmlElement(element)) {

339

throw new Error('Drop zone must be an HTML element');

340

}

341

342

element.addEventListener('drop', async (event) => {

343

event.preventDefault();

344

345

const files = event.dataTransfer?.files;

346

if (files) {

347

for (const file of Array.from(files)) {

348

try {

349

const formData = await handleFileUpload(file);

350

console.log('File ready for upload:', formData);

351

} catch (error) {

352

console.error('File upload error:', error);

353

}

354

}

355

}

356

});

357

}

358

```

359

360

### URL and Query Parameter Handling

361

362

```typescript

363

import is from '@sindresorhus/is';

364

365

function parseUrl(input: unknown): {url: URL; params: Record<string, string>} {

366

let url: URL;

367

368

if (is.urlInstance(input)) {

369

url = input;

370

} else if (is.string(input)) {

371

try {

372

url = new URL(input);

373

} catch {

374

throw new Error('Invalid URL string');

375

}

376

} else {

377

throw new Error('Input must be URL instance or string');

378

}

379

380

const params: Record<string, string> = {};

381

for (const [key, value] of url.searchParams.entries()) {

382

params[key] = value;

383

}

384

385

return { url, params };

386

}

387

388

function buildApiUrl(baseUrl: string, endpoint: string, params?: unknown): string {

389

const url = new URL(endpoint, baseUrl);

390

391

if (params) {

392

let searchParams: URLSearchParams;

393

394

if (is.urlSearchParams(params)) {

395

searchParams = params;

396

} else if (is.plainObject(params)) {

397

searchParams = new URLSearchParams(params as Record<string, string>);

398

} else {

399

throw new Error('Params must be URLSearchParams or plain object');

400

}

401

402

url.search = searchParams.toString();

403

}

404

405

return url.toString();

406

}

407

```

408

409

### Form Data Processing

410

411

```typescript

412

import is from '@sindresorhus/is';

413

414

function extractFormData(form: unknown): Record<string, string | File> {

415

if (!is.htmlElement(form) || form.tagName !== 'FORM') {

416

throw new Error('Input must be a form element');

417

}

418

419

const formData = new FormData(form as HTMLFormElement);

420

const result: Record<string, string | File> = {};

421

422

for (const [key, value] of formData.entries()) {

423

if (is.string(value)) {

424

result[key] = value;

425

} else if (is.blob(value)) {

426

result[key] = value as File;

427

}

428

}

429

430

return result;

431

}

432

433

function validateFormData(data: unknown): FormData {

434

if (!is.formData(data)) {

435

throw new Error('Input must be FormData');

436

}

437

438

// Validate required fields

439

const requiredFields = ['name', 'email'];

440

for (const field of requiredFields) {

441

if (!data.has(field)) {

442

throw new Error(`Missing required field: ${field}`);

443

}

444

}

445

446

return data;

447

}

448

```

449

450

## Notes

451

452

- HTML element checking validates DOM elements but not other node types (text, comment, etc.)

453

- Blob checking includes File objects since File extends Blob

454

- FormData is useful for multipart form submissions and file uploads

455

- URL instance checking validates URL objects, not URL strings (use `isUrlString()` for strings)

456

- URLSearchParams provides easy query string manipulation

457

- Web API checks are browser-specific and may not work in Node.js environments

458

- All web API checks work with TypeScript type guards for compile-time type narrowing

459

- Consider environment detection before using these checks in universal/isomorphic code