Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/janjakubnanista/ts-type-checked
Runtime duck type checking utilities for TypeScript.
https://github.com/janjakubnanista/ts-type-checked
duck-typing guards type-guards type-safety typescript typing
Last synced: 12 days ago
JSON representation
Runtime duck type checking utilities for TypeScript.
- Host: GitHub
- URL: https://github.com/janjakubnanista/ts-type-checked
- Owner: janjakubnanista
- License: mit
- Created: 2020-03-18T19:33:41.000Z (over 4 years ago)
- Default Branch: main
- Last Pushed: 2023-03-04T12:04:30.000Z (over 1 year ago)
- Last Synced: 2024-10-16T12:46:38.641Z (27 days ago)
- Topics: duck-typing, guards, type-guards, type-safety, typescript, typing
- Language: TypeScript
- Size: 3.74 MB
- Stars: 87
- Watchers: 1
- Forks: 5
- Open Issues: 24
-
Metadata Files:
- Readme: README.md
- Contributing: docs/CONTRIBUTING.md
- License: LICENSE
- Support: docs/SUPPORTED_TYPES.md
Awesome Lists containing this project
README
ts-type-checked
Automatic type guards for TypeScript
ts-type-checked
generates type guards based on your own (or library) TypeScript types.
It is compatible with
Rollup,
Webpack and
ttypescript projects
and works nicely with
Jest,
Mocha or
ts-node
Example cases
|
Installation
|
API
|
Supported types## Wait what?
As they say *an example is worth a thousand API docs* so why not start with one.
```typescript
interface WelcomeMessage {
name: string;
hobbies: string[];
}//
// You can now turn this
//
const isWelcomeMessage = (value: any): message is WelcomeMessage =>
!!value &&
typeof value.name === 'string' &&
Array.isArray(value.hobbies) &&
value.hobbies.every(hobby => typeof hobby === 'string');//
// Into this
//
const isWelcomeMessage = typeCheckFor();//
// Or without creating a function
//
if (isA(value)) {
// value is a WelcomeMessage!
}
```## Motivation
TypeScript is a powerful way of enhancing your application code at compile time but, unfortunately, provides no runtime type guards out of the box - you need to [create these manually](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards). For types like `string` or `boolean` this is easy, you can just use the `typeof` operator. It becomes more difficult for interface types, arrays, enums etc.
**And that is where `ts-type-checked` comes in!** It automatically creates these type guards at compile time for you.
This might get useful when:
- You want to make sure an object you received from an API matches the expected type
- You are exposing your code as a library and want to prevent users from passing in invalid arguments
- You want to check whether a variable implements one of more possible interfaces (e.g. `LoggedInUser`, `GuestUser`)
- _..._## Example cases
### Checking external data
Imagine your [API spec](https://swagger.io/) promises to respond with objects like these:
```typescript
interface WelcomeMessage {
name: string;
greeting: string;
}interface GoodbyeMessage {
sayByeTo: string[];
}
```Somewhere in your code there probably is a function just like `handleResponse` below:
```typescript
function handleResponse(data: string): string {
const message = JSON.parse(data);if (isWelcomeMessage(message)) {
return 'Good day dear ' + message.name!
}if (isGoodbyeMessage(message)) {
return 'I will say bye to ' + message.sayByeTo.join(', ');
}throw new Error('I have no idea what you mean');
}
```If you now need to find out whether you received a valid response, you end up defining helper functions like `isWelcomeMessage` and `isGoodbyeMessage` below.
```typescript
const isWelcomeMessage = (value: any): value is WelcomeMessage =>
!!value &&
typeof value.name === 'string' &&
typeof value.greeting === 'string';const isGoodbyeMessage = (value: any): value is GoodbyeMessage =>
!!value &&
Array.isArray(value.sayByeTo) &&
value.sayByeTo.every(name => typeof name === 'string');
```Annoying isn't it? Not only you need to define the guards yourself, you also need to make sure the types and the type guards don't drift apart as the code evolves. Let's try using `ts-type-checked`:
```typescript
import { isA, typeCheckFor } from 'ts-type-checked';// You can use typeCheckFor type guard factory
const isWelcomeMessage = typeCheckFor();
const isGoodbyeMessage = typeCheckFor();// Or use isA generic type guard directly in your code
if (isA(message)) {
// ...
}
```### Type guard factories
`ts-type-checked` exports `typeCheckFor` type guard factory. This is more or less a syntactic sugar that saves you couple of keystrokes. It is useful when you want to store the type guard into a variable or pass it as a parameter:
```typescript
import { typeCheckFor } from 'ts-type-checked';interface Config {
version: string;
}const isConfig = typeCheckFor();
const isString = typeCheckFor();function handleArray(array: unknown[]) {
const strings = array.filter(isString);
const configs = array.filter(isConfig);
}// Without typeCheckFor you'd need to write
const isConfig = (value: unknown): value is Config => isA(value);
const isString = (value: unknown): value is Config => isA(value);
```### Reducing the size of generated code
`isA` and `typeCheckFor` will both transform the code on per-file basis - in other terms a type guard function will be created in every file where either of these is used. To prevent duplication of generated code I recommend placing the type guards in a separate file and importing them when necessary:
```typescript
// in file typeGuards.ts
import { typeCheckFor } from 'ts-type-checked';export const isDate = typeCheckFor();
export const isStringRecord = typeCheckFor>();// in file myUtility.ts
import { isDate } from './typeGuards';if (isDate(value)) {
// ...
}
```## Useful links
- [ts-trasformer-keys](https://www.npmjs.com/package/ts-transformer-keys), TypeScript transformer that gives you access to interface properties
- [ts-auto-mock](https://www.npmjs.com/package/ts-auto-mock), TypeScript transformer that generates mock data objects based on your types