Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export { pushDataWithSchemaRepair, isSchemaValidationError } from './src/pushDataWithSchemaRepair.js';
export { pushDataWithSchemaRepair, isSchemaValidationError } from './src/push-data-with-schema-repair/index.js';
export type {
ValidationError,
DroppedItem,
PushDataWithSchemaRepairResult,
PushDataWithSchemaRepairOptions,
PushFn,
} from './src/pushDataWithSchemaRepair.js';
} from './src/push-data-with-schema-repair/index.js';
38 changes: 4 additions & 34 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./push-data-with-schema-repair": {
"types": "./dist/src/push-data-with-schema-repair/index.d.ts",
"default": "./dist/src/push-data-with-schema-repair/index.js"
},
"./qc-logger": {
"types": "./dist/src/qc-logger/index.d.ts",
"default": "./dist/src/qc-logger/index.js"
Expand Down
57 changes: 57 additions & 0 deletions src/type-utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# type-utils

`@apify/actor-utils/type-utils` is a separate export holding small,
dependency-free TypeScript helpers — one runtime function and a set of
type-level operators. It imports nothing, so pulling it in costs nothing
beyond the helpers themselves.

```ts
import { unreachable } from '@apify/actor-utils/type-utils';
import type { Truthy, Falsy, Nullish, Defined } from '@apify/actor-utils/type-utils';
```

## `unreachable(x: never): never`

Asserts a code path can't be reached, giving you a compile-time
exhaustiveness check. Pass a value that should be `never` — if a new union
variant is added but not handled, `x` is no longer `never` and the call
fails to compile. At runtime it always throws.

```ts
type Shape = 'circle' | 'square';

function area(shape: Shape): number {
switch (shape) {
case 'circle':
return Math.PI;
case 'square':
return 1;
default:
// Compile-time error here if a new Shape variant is added.
return unreachable(shape);
}
}
```

## Type-level helpers

| Type | Result |
| ------------ | ---------------------------------------------------------------- |
| `Falsy` | `false \| 0 \| '' \| null \| undefined` — the falsy primitives. |
| `Nullish` | `null \| undefined`. |
| `Defined<T>` | `T` with `null` and `undefined` removed (`Exclude<T, Nullish>`). |
| `Truthy<T>` | `T` narrowed to only its truthy members. |

```ts
type A = Truthy<string | undefined>; // string
type B = Truthy<0 | 1 | 2>; // 1 | 2
type C = Truthy<'' | 'hello'>; // 'hello'
type D = Truthy<false>; // never
```

`Truthy` checks each falsy literal individually rather than using
`Exclude<T, Falsy>`, so a broad type like `boolean` or `number` is preserved
instead of collapsed — `boolean` only loses `false` when `false` is the
whole type, not when it's one member of `boolean`. Object types
short-circuit first, so `''` / `0` never accidentally match structural
(`{}`) types.
1 change: 1 addition & 0 deletions src/type-utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { unreachable } from './unreachable.js';
export type { Falsy, Nullish, Truthy, Defined } from './types.js';
export { type NonEmptyList, isNonEmptyList } from './non-empty.js';
39 changes: 39 additions & 0 deletions src/type-utils/non-empty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* An array of `T` guaranteed to hold at least one element.
*
* Modelled as a tuple with a required head and a variadic tail (`[T, ...T[]]`),
* so the compiler knows `list[0]` always exists and treats it as `T` rather
* than `T | undefined`. Narrow a plain `T[]` to this with {@link isNonEmptyList}.
*
* @example
* ```ts
* function first<T>(list: NonEmptyList<T>): T {
* return list[0]; // safe: no undefined
* }
* ```
*/
export type NonEmptyList<T> = [T, ...T[]];

/**
* Type guard that narrows an array to a {@link NonEmptyList} when it holds at
* least one element.
*
* Use it to let the compiler know `list[0]` is safe to access after the check,
* without a non-null assertion.
*
* @param list - The array to check.
* @returns `true` if `list` has at least one element, narrowing it to
* `NonEmptyList<T>`.
*
* @example
* ```ts
* const items: number[] = getItems();
*
* if (isNonEmptyList(items)) {
* const first = items[0]; // typed as number, not number | undefined
* }
* ```
*/
export function isNonEmptyList<T>(list: T[]): list is NonEmptyList<T> {
return Boolean(list.length);
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
pushDataWithSchemaRepair,
type PushFn,
type ValidationError,
} from '../src/pushDataWithSchemaRepair.js';
} from '../../src/push-data-with-schema-repair/index.js';

// Shape of an item used across tests.
interface Item {
Expand Down
Loading