@datocms/cma-client 5.4.6 → 5.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -3
- package/dist/cjs/generated/Client.js +1 -1
- package/dist/cjs/utilities/isBlockOfType.js +5 -33
- package/dist/cjs/utilities/isBlockOfType.js.map +1 -1
- package/dist/esm/generated/Client.js +1 -1
- package/dist/esm/utilities/isBlockOfType.d.ts +20 -7
- package/dist/esm/utilities/isBlockOfType.js +5 -33
- package/dist/esm/utilities/isBlockOfType.js.map +1 -1
- package/dist/types/utilities/isBlockOfType.d.ts +20 -7
- package/package.json +2 -2
- package/src/generated/Client.ts +1 -1
- package/src/utilities/isBlockOfType.ts +31 -9
package/README.md
CHANGED
|
@@ -309,10 +309,17 @@ TypeScript doesn't auto-narrow on discriminators buried in nested properties, so
|
|
|
309
309
|
|
|
310
310
|
**TypeScript Signature:**
|
|
311
311
|
```typescript
|
|
312
|
+
// Curried — returns a predicate (use with .filter / .find)
|
|
312
313
|
function isBlockOfType<Id extends string>(
|
|
313
314
|
itemTypeId: Id,
|
|
314
315
|
): <T>(block: T) => block is NarrowBlockByItemType<T, Id>
|
|
315
316
|
|
|
317
|
+
// Direct — checks a single block inline (use inside `if`)
|
|
318
|
+
function isBlockOfType<T, Id extends string>(
|
|
319
|
+
itemTypeId: Id,
|
|
320
|
+
block: T,
|
|
321
|
+
): block is NarrowBlockByItemType<T, Id>
|
|
322
|
+
|
|
316
323
|
type NarrowBlockByItemType<T, Id extends string> = Extract<
|
|
317
324
|
T,
|
|
318
325
|
{ relationships: { item_type: { data: { type: 'item_type'; id: Id } } } }
|
|
@@ -321,8 +328,13 @@ type NarrowBlockByItemType<T, Id extends string> = Extract<
|
|
|
321
328
|
|
|
322
329
|
**Parameters:**
|
|
323
330
|
- `itemTypeId`: The item-type ID literal. For narrowing to work, the argument must be typed as a literal — use `as const` on pre-set ID constants. No `ItemTypeDefinition` type parameter is needed: `Extract` walks the input union using just the ID.
|
|
331
|
+
- `block` (direct form only): The block to check.
|
|
332
|
+
|
|
333
|
+
**Returns:**
|
|
334
|
+
- Curried form: a predicate `(block) => block is D-typed-block`.
|
|
335
|
+
- Direct form: a `boolean` that also acts as a type guard on `block`.
|
|
324
336
|
|
|
325
|
-
|
|
337
|
+
In both cases the guard:
|
|
326
338
|
- Narrows blocks carrying `relationships.item_type.data.id` — that covers `BlockInNestedResponse<D>` and the object variants of `BlockInRequest<D>` (`UpdatedBlockInRequest`, `NewBlockInRequest`).
|
|
327
339
|
- Returns `false` for plain string IDs (unchanged-reference form in request payloads) and for any non-block input.
|
|
328
340
|
|
|
@@ -343,12 +355,18 @@ const images = article.content.filter(
|
|
|
343
355
|
);
|
|
344
356
|
images[0].attributes.upload_id; // ❌ property does not exist on union
|
|
345
357
|
|
|
346
|
-
// After: guard narrows the filter result
|
|
358
|
+
// After (curried): guard narrows the filter result
|
|
347
359
|
const images = article.content.filter(isBlockOfType(IMAGE_BLOCK_ID));
|
|
348
360
|
images[0].attributes.upload_id; // ✅ narrowed
|
|
361
|
+
|
|
362
|
+
// After (direct): inline narrowing on a single block
|
|
363
|
+
const first = article.content[0];
|
|
364
|
+
if (isBlockOfType(IMAGE_BLOCK_ID, first)) {
|
|
365
|
+
first.attributes.upload_id; // ✅ narrowed
|
|
366
|
+
}
|
|
349
367
|
```
|
|
350
368
|
|
|
351
|
-
Use the
|
|
369
|
+
Use the curried form when you need a predicate for `.filter` / `.find`; use the direct form for one-off `if` checks. The `__itemTypeId` discriminator is also available for inline `switch` narrowing on a single value.
|
|
352
370
|
</details>
|
|
353
371
|
|
|
354
372
|
### Recursive Block Operations
|
|
@@ -90,7 +90,7 @@ class Client {
|
|
|
90
90
|
return this.config.baseUrl || Client.defaultBaseUrl;
|
|
91
91
|
}
|
|
92
92
|
request(options) {
|
|
93
|
-
return (0, rest_client_utils_1.request)(Object.assign(Object.assign(Object.assign({}, this.config), options), { logFn: this.config.logFn || console.log, userAgent: '@datocms/cma-client v5.4.
|
|
93
|
+
return (0, rest_client_utils_1.request)(Object.assign(Object.assign(Object.assign({}, this.config), options), { logFn: this.config.logFn || console.log, userAgent: '@datocms/cma-client v5.4.7', baseUrl: this.baseUrl, preCallStack: new Error().stack, extraHeaders: Object.assign(Object.assign(Object.assign({}, (this.config.extraHeaders || {})), (this.config.environment
|
|
94
94
|
? { 'X-Environment': this.config.environment }
|
|
95
95
|
: {})), { 'X-API-Version': '3' }), fetchJobResult: (jobId) => {
|
|
96
96
|
return this.jobResultsFetcher
|
|
@@ -1,39 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isBlockOfType = void 0;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*
|
|
7
|
-
* Call it with the block's `itemTypeId` literal — the ID generic is inferred
|
|
8
|
-
* from the argument, so no explicit type parameter is needed. The returned
|
|
9
|
-
* predicate is generic: given any input type `T`, it narrows to
|
|
10
|
-
* `Extract<T, { relationships: { item_type: { data: { id: Id } } } }>`. It's
|
|
11
|
-
* meant to plug into `Array#filter` / `Array#find` over block-bearing fields
|
|
12
|
-
* in any of these contexts:
|
|
13
|
-
*
|
|
14
|
-
* - `ItemInNestedResponse<D>` (responses with `nested: true`)
|
|
15
|
-
* - `ItemCreateSchema<D>` / `ItemUpdateSchema<D>` (request payloads, object
|
|
16
|
-
* variants; plain string IDs are filtered out — there's no way to narrow
|
|
17
|
-
* them without an external lookup)
|
|
18
|
-
*
|
|
19
|
-
* The default (non-nested) response shape, where block fields are arrays of
|
|
20
|
-
* plain string IDs, is deliberately not supported — the type information is
|
|
21
|
-
* not recoverable from an ID alone.
|
|
22
|
-
*
|
|
23
|
-
* For the literal `Id` to be preserved (and narrowing to work), the argument
|
|
24
|
-
* must be typed as a literal — use `as const` on pre-set ID constants.
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```ts
|
|
28
|
-
* const SESSION_BLOCK_ID = 'abc123' as const;
|
|
29
|
-
*
|
|
30
|
-
* const record = await client.items.find<Schema.ConferenceDay>(id, { nested: true });
|
|
31
|
-
* const sessions = record.agenda.filter(isBlockOfType(SESSION_BLOCK_ID));
|
|
32
|
-
* sessions[0].attributes.signup_url; // OK — narrowed
|
|
33
|
-
* ```
|
|
34
|
-
*/
|
|
35
|
-
function isBlockOfType(itemTypeId) {
|
|
36
|
-
return (block) => {
|
|
4
|
+
function isBlockOfType(itemTypeId, ...rest) {
|
|
5
|
+
const check = (block) => {
|
|
37
6
|
if (typeof block !== 'object' || block === null)
|
|
38
7
|
return false;
|
|
39
8
|
const relationships = block.relationships;
|
|
@@ -47,6 +16,9 @@ function isBlockOfType(itemTypeId) {
|
|
|
47
16
|
return false;
|
|
48
17
|
return data.id === itemTypeId;
|
|
49
18
|
};
|
|
19
|
+
if (rest.length > 0)
|
|
20
|
+
return check(rest[0]);
|
|
21
|
+
return (block) => check(block);
|
|
50
22
|
}
|
|
51
23
|
exports.isBlockOfType = isBlockOfType;
|
|
52
24
|
//# sourceMappingURL=isBlockOfType.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isBlockOfType.js","sourceRoot":"","sources":["../../../src/utilities/isBlockOfType.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"isBlockOfType.js","sourceRoot":"","sources":["../../../src/utilities/isBlockOfType.ts"],"names":[],"mappings":";;;AAiEA,SAAgB,aAAa,CAC3B,UAAc,EACd,GAAG,IAA2B;IAE9B,MAAM,KAAK,GAAG,CAAC,KAAc,EAAW,EAAE;QACxC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAC9D,MAAM,aAAa,GAAI,KAAqC,CAAC,aAAa,CAAC;QAC3E,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,KAAK,IAAI;YAC7D,OAAO,KAAK,CAAC;QACf,MAAM,QAAQ,GAAI,aAAyC,CAAC,SAAS,CAAC;QACtE,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QACpE,MAAM,IAAI,GAAI,QAA+B,CAAC,IAAI,CAAC;QACnD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAC5D,OAAQ,IAAyB,CAAC,EAAE,KAAK,UAAU,CAAC;IACtD,CAAC,CAAC;IACF,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,OAAO,CAAI,KAAQ,EAAyC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAjBD,sCAiBC"}
|
|
@@ -64,7 +64,7 @@ export class Client {
|
|
|
64
64
|
return this.config.baseUrl || Client.defaultBaseUrl;
|
|
65
65
|
}
|
|
66
66
|
request(options) {
|
|
67
|
-
return request(Object.assign(Object.assign(Object.assign({}, this.config), options), { logFn: this.config.logFn || console.log, userAgent: '@datocms/cma-client v5.4.
|
|
67
|
+
return request(Object.assign(Object.assign(Object.assign({}, this.config), options), { logFn: this.config.logFn || console.log, userAgent: '@datocms/cma-client v5.4.7', baseUrl: this.baseUrl, preCallStack: new Error().stack, extraHeaders: Object.assign(Object.assign(Object.assign({}, (this.config.extraHeaders || {})), (this.config.environment
|
|
68
68
|
? { 'X-Environment': this.config.environment }
|
|
69
69
|
: {})), { 'X-API-Version': '3' }), fetchJobResult: (jobId) => {
|
|
70
70
|
return this.jobResultsFetcher
|
|
@@ -19,14 +19,19 @@ export type NarrowBlockByItemType<T, Id extends string> = Extract<T, {
|
|
|
19
19
|
};
|
|
20
20
|
}>;
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* Type guard that narrows a block to a specific model.
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
24
|
+
* Two call styles, same narrowing behavior:
|
|
25
|
+
*
|
|
26
|
+
* - Curried: `isBlockOfType(itemTypeId)` returns a predicate, ideal for
|
|
27
|
+
* `Array#filter` / `Array#find`.
|
|
28
|
+
* - Direct: `isBlockOfType(itemTypeId, block)` checks a single value inline,
|
|
29
|
+
* handy inside `if` statements when you already have the block in hand.
|
|
30
|
+
*
|
|
31
|
+
* The ID generic is inferred from the first argument, so no explicit type
|
|
32
|
+
* parameter is needed. Given any input type `T`, the result narrows to
|
|
33
|
+
* `Extract<T, { relationships: { item_type: { data: { id: Id } } } }>`,
|
|
34
|
+
* which covers:
|
|
30
35
|
*
|
|
31
36
|
* - `ItemInNestedResponse<D>` (responses with `nested: true`)
|
|
32
37
|
* - `ItemCreateSchema<D>` / `ItemUpdateSchema<D>` (request payloads, object
|
|
@@ -45,8 +50,16 @@ export type NarrowBlockByItemType<T, Id extends string> = Extract<T, {
|
|
|
45
50
|
* const SESSION_BLOCK_ID = 'abc123' as const;
|
|
46
51
|
*
|
|
47
52
|
* const record = await client.items.find<Schema.ConferenceDay>(id, { nested: true });
|
|
53
|
+
*
|
|
54
|
+
* // Curried — predicate for filter/find
|
|
48
55
|
* const sessions = record.agenda.filter(isBlockOfType(SESSION_BLOCK_ID));
|
|
49
56
|
* sessions[0].attributes.signup_url; // OK — narrowed
|
|
57
|
+
*
|
|
58
|
+
* // Direct — inline check on a single block
|
|
59
|
+
* if (isBlockOfType(SESSION_BLOCK_ID, record.agenda[0])) {
|
|
60
|
+
* record.agenda[0].attributes.signup_url; // OK — narrowed
|
|
61
|
+
* }
|
|
50
62
|
* ```
|
|
51
63
|
*/
|
|
52
64
|
export declare function isBlockOfType<Id extends string>(itemTypeId: Id): <T>(block: T) => block is NarrowBlockByItemType<T, Id>;
|
|
65
|
+
export declare function isBlockOfType<T, Id extends string>(itemTypeId: Id, block: T): block is NarrowBlockByItemType<T, Id>;
|
|
@@ -1,36 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Call it with the block's `itemTypeId` literal — the ID generic is inferred
|
|
5
|
-
* from the argument, so no explicit type parameter is needed. The returned
|
|
6
|
-
* predicate is generic: given any input type `T`, it narrows to
|
|
7
|
-
* `Extract<T, { relationships: { item_type: { data: { id: Id } } } }>`. It's
|
|
8
|
-
* meant to plug into `Array#filter` / `Array#find` over block-bearing fields
|
|
9
|
-
* in any of these contexts:
|
|
10
|
-
*
|
|
11
|
-
* - `ItemInNestedResponse<D>` (responses with `nested: true`)
|
|
12
|
-
* - `ItemCreateSchema<D>` / `ItemUpdateSchema<D>` (request payloads, object
|
|
13
|
-
* variants; plain string IDs are filtered out — there's no way to narrow
|
|
14
|
-
* them without an external lookup)
|
|
15
|
-
*
|
|
16
|
-
* The default (non-nested) response shape, where block fields are arrays of
|
|
17
|
-
* plain string IDs, is deliberately not supported — the type information is
|
|
18
|
-
* not recoverable from an ID alone.
|
|
19
|
-
*
|
|
20
|
-
* For the literal `Id` to be preserved (and narrowing to work), the argument
|
|
21
|
-
* must be typed as a literal — use `as const` on pre-set ID constants.
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```ts
|
|
25
|
-
* const SESSION_BLOCK_ID = 'abc123' as const;
|
|
26
|
-
*
|
|
27
|
-
* const record = await client.items.find<Schema.ConferenceDay>(id, { nested: true });
|
|
28
|
-
* const sessions = record.agenda.filter(isBlockOfType(SESSION_BLOCK_ID));
|
|
29
|
-
* sessions[0].attributes.signup_url; // OK — narrowed
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
|
-
export function isBlockOfType(itemTypeId) {
|
|
33
|
-
return (block) => {
|
|
1
|
+
export function isBlockOfType(itemTypeId, ...rest) {
|
|
2
|
+
const check = (block) => {
|
|
34
3
|
if (typeof block !== 'object' || block === null)
|
|
35
4
|
return false;
|
|
36
5
|
const relationships = block.relationships;
|
|
@@ -44,5 +13,8 @@ export function isBlockOfType(itemTypeId) {
|
|
|
44
13
|
return false;
|
|
45
14
|
return data.id === itemTypeId;
|
|
46
15
|
};
|
|
16
|
+
if (rest.length > 0)
|
|
17
|
+
return check(rest[0]);
|
|
18
|
+
return (block) => check(block);
|
|
47
19
|
}
|
|
48
20
|
//# sourceMappingURL=isBlockOfType.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"isBlockOfType.js","sourceRoot":"","sources":["../../../src/utilities/isBlockOfType.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"isBlockOfType.js","sourceRoot":"","sources":["../../../src/utilities/isBlockOfType.ts"],"names":[],"mappings":"AAiEA,MAAM,UAAU,aAAa,CAC3B,UAAc,EACd,GAAG,IAA2B;IAE9B,MAAM,KAAK,GAAG,CAAC,KAAc,EAAW,EAAE;QACxC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAC9D,MAAM,aAAa,GAAI,KAAqC,CAAC,aAAa,CAAC;QAC3E,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,KAAK,IAAI;YAC7D,OAAO,KAAK,CAAC;QACf,MAAM,QAAQ,GAAI,aAAyC,CAAC,SAAS,CAAC;QACtE,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QACpE,MAAM,IAAI,GAAI,QAA+B,CAAC,IAAI,CAAC;QACnD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAC5D,OAAQ,IAAyB,CAAC,EAAE,KAAK,UAAU,CAAC;IACtD,CAAC,CAAC;IACF,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3C,OAAO,CAAI,KAAQ,EAAyC,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC"}
|
|
@@ -19,14 +19,19 @@ export type NarrowBlockByItemType<T, Id extends string> = Extract<T, {
|
|
|
19
19
|
};
|
|
20
20
|
}>;
|
|
21
21
|
/**
|
|
22
|
-
*
|
|
22
|
+
* Type guard that narrows a block to a specific model.
|
|
23
23
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
24
|
+
* Two call styles, same narrowing behavior:
|
|
25
|
+
*
|
|
26
|
+
* - Curried: `isBlockOfType(itemTypeId)` returns a predicate, ideal for
|
|
27
|
+
* `Array#filter` / `Array#find`.
|
|
28
|
+
* - Direct: `isBlockOfType(itemTypeId, block)` checks a single value inline,
|
|
29
|
+
* handy inside `if` statements when you already have the block in hand.
|
|
30
|
+
*
|
|
31
|
+
* The ID generic is inferred from the first argument, so no explicit type
|
|
32
|
+
* parameter is needed. Given any input type `T`, the result narrows to
|
|
33
|
+
* `Extract<T, { relationships: { item_type: { data: { id: Id } } } }>`,
|
|
34
|
+
* which covers:
|
|
30
35
|
*
|
|
31
36
|
* - `ItemInNestedResponse<D>` (responses with `nested: true`)
|
|
32
37
|
* - `ItemCreateSchema<D>` / `ItemUpdateSchema<D>` (request payloads, object
|
|
@@ -45,8 +50,16 @@ export type NarrowBlockByItemType<T, Id extends string> = Extract<T, {
|
|
|
45
50
|
* const SESSION_BLOCK_ID = 'abc123' as const;
|
|
46
51
|
*
|
|
47
52
|
* const record = await client.items.find<Schema.ConferenceDay>(id, { nested: true });
|
|
53
|
+
*
|
|
54
|
+
* // Curried — predicate for filter/find
|
|
48
55
|
* const sessions = record.agenda.filter(isBlockOfType(SESSION_BLOCK_ID));
|
|
49
56
|
* sessions[0].attributes.signup_url; // OK — narrowed
|
|
57
|
+
*
|
|
58
|
+
* // Direct — inline check on a single block
|
|
59
|
+
* if (isBlockOfType(SESSION_BLOCK_ID, record.agenda[0])) {
|
|
60
|
+
* record.agenda[0].attributes.signup_url; // OK — narrowed
|
|
61
|
+
* }
|
|
50
62
|
* ```
|
|
51
63
|
*/
|
|
52
64
|
export declare function isBlockOfType<Id extends string>(itemTypeId: Id): <T>(block: T) => block is NarrowBlockByItemType<T, Id>;
|
|
65
|
+
export declare function isBlockOfType<T, Id extends string>(itemTypeId: Id, block: T): block is NarrowBlockByItemType<T, Id>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datocms/cma-client",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.7",
|
|
4
4
|
"description": "JS client for DatoCMS REST Content Management API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"datocms",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"@datocms/dashboard-client": "^5.4.3",
|
|
46
46
|
"@types/uuid": "^9.0.7"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "4a2443c6f351448a165eef4359a3451ffd5b6b08"
|
|
49
49
|
}
|
package/src/generated/Client.ts
CHANGED
|
@@ -151,7 +151,7 @@ export class Client {
|
|
|
151
151
|
...this.config,
|
|
152
152
|
...options,
|
|
153
153
|
logFn: this.config.logFn || console.log,
|
|
154
|
-
userAgent: '@datocms/cma-client v5.4.
|
|
154
|
+
userAgent: '@datocms/cma-client v5.4.7',
|
|
155
155
|
baseUrl: this.baseUrl,
|
|
156
156
|
preCallStack: new Error().stack,
|
|
157
157
|
extraHeaders: {
|
|
@@ -14,14 +14,19 @@ export type NarrowBlockByItemType<T, Id extends string> = Extract<
|
|
|
14
14
|
>;
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
* Type guard that narrows a block to a specific model.
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
19
|
+
* Two call styles, same narrowing behavior:
|
|
20
|
+
*
|
|
21
|
+
* - Curried: `isBlockOfType(itemTypeId)` returns a predicate, ideal for
|
|
22
|
+
* `Array#filter` / `Array#find`.
|
|
23
|
+
* - Direct: `isBlockOfType(itemTypeId, block)` checks a single value inline,
|
|
24
|
+
* handy inside `if` statements when you already have the block in hand.
|
|
25
|
+
*
|
|
26
|
+
* The ID generic is inferred from the first argument, so no explicit type
|
|
27
|
+
* parameter is needed. Given any input type `T`, the result narrows to
|
|
28
|
+
* `Extract<T, { relationships: { item_type: { data: { id: Id } } } }>`,
|
|
29
|
+
* which covers:
|
|
25
30
|
*
|
|
26
31
|
* - `ItemInNestedResponse<D>` (responses with `nested: true`)
|
|
27
32
|
* - `ItemCreateSchema<D>` / `ItemUpdateSchema<D>` (request payloads, object
|
|
@@ -40,14 +45,29 @@ export type NarrowBlockByItemType<T, Id extends string> = Extract<
|
|
|
40
45
|
* const SESSION_BLOCK_ID = 'abc123' as const;
|
|
41
46
|
*
|
|
42
47
|
* const record = await client.items.find<Schema.ConferenceDay>(id, { nested: true });
|
|
48
|
+
*
|
|
49
|
+
* // Curried — predicate for filter/find
|
|
43
50
|
* const sessions = record.agenda.filter(isBlockOfType(SESSION_BLOCK_ID));
|
|
44
51
|
* sessions[0].attributes.signup_url; // OK — narrowed
|
|
52
|
+
*
|
|
53
|
+
* // Direct — inline check on a single block
|
|
54
|
+
* if (isBlockOfType(SESSION_BLOCK_ID, record.agenda[0])) {
|
|
55
|
+
* record.agenda[0].attributes.signup_url; // OK — narrowed
|
|
56
|
+
* }
|
|
45
57
|
* ```
|
|
46
58
|
*/
|
|
47
59
|
export function isBlockOfType<Id extends string>(
|
|
48
60
|
itemTypeId: Id,
|
|
49
|
-
): <T>(block: T) => block is NarrowBlockByItemType<T, Id
|
|
50
|
-
|
|
61
|
+
): <T>(block: T) => block is NarrowBlockByItemType<T, Id>;
|
|
62
|
+
export function isBlockOfType<T, Id extends string>(
|
|
63
|
+
itemTypeId: Id,
|
|
64
|
+
block: T,
|
|
65
|
+
): block is NarrowBlockByItemType<T, Id>;
|
|
66
|
+
export function isBlockOfType<Id extends string>(
|
|
67
|
+
itemTypeId: Id,
|
|
68
|
+
...rest: [block: unknown] | []
|
|
69
|
+
): boolean | (<T>(block: T) => block is NarrowBlockByItemType<T, Id>) {
|
|
70
|
+
const check = (block: unknown): boolean => {
|
|
51
71
|
if (typeof block !== 'object' || block === null) return false;
|
|
52
72
|
const relationships = (block as { relationships?: unknown }).relationships;
|
|
53
73
|
if (typeof relationships !== 'object' || relationships === null)
|
|
@@ -58,4 +78,6 @@ export function isBlockOfType<Id extends string>(
|
|
|
58
78
|
if (typeof data !== 'object' || data === null) return false;
|
|
59
79
|
return (data as { id?: unknown }).id === itemTypeId;
|
|
60
80
|
};
|
|
81
|
+
if (rest.length > 0) return check(rest[0]);
|
|
82
|
+
return <T>(block: T): block is NarrowBlockByItemType<T, Id> => check(block);
|
|
61
83
|
}
|