ts-interface-loader icon indicating copy to clipboard operation
ts-interface-loader copied to clipboard

Webpack support for validating TypeScript definitions at runtime.

ts-interface-loader

Build Status codecov License Contributor Covenant

Validate TypeScript definitions at runtime with webpack and Node 8+. Built and used at Spotify.

Common use cases:

  • Provide validation for JSON files (i.e. system config)
  • Testing JSON output using your existing TypeScript definitions.

Intro

By design, TypeScript only provides typechecking at compile time. However it is possible to do so at runtime through ts-interface-builder generating a JSON manifest of your definitions and ts-interface-checker for validating those types with plain JSON / JavaScript objects.

In our case, we wanted to build the manifest automatically through Webpack. Welcome ts-interface-loader!

Code Example

How does it look like in code terms?

// First, we'll want to make some TypeScript definitions.
// In this case, we have a types.ts with a IUser type interface.
//
export interface IUser {
  first_name: string
  last_name: string
  office_location: 'stockholm' | 'gothenburg' | 'london' | 'new york' | 'boston'
}

// Secondly, we'll write our app.ts (which will run with Webpack)
//
import {createCheckers, ITypeSuite} from 'ts-interface-checker'
import typesTI from 'ts-interface-loader!./types'
// import {IUser} from './types'

const validPayload = {first_name: 'Daniel', last_name: 'Ek'}
const invalidPayload = {first_name: 'Daniel', last_name: 123}

try {
  createCheckers(typesTI).IUser.check(invalidPayload)
} catch (err) {
  console.log(err.message) // => "value.last_name is not a string"
}

// Or, if we want to validate in "strict" mode
// It's the same as above, except column presence is required.
//
const validStrictPayload = {first_name: 'Daniel', last_name: 'Ek', office_location: 'stockholm'}
const invalidStrictPayload = {first_name: 'Daniel', last_name: 'Ek'}

try {
  createCheckers(typesTI).IUser.strictCheck(invalidStrictPayload)
} catch (err) {
  console.log(err.message) // => "value.office_location is missing"
}

For a more in-depth sample, take a look at our sample project.

Getting started

Install

$ npm install --dev ts-interface-loader
$ yarn add --dev ts-interface-loader

Import ts-interface-loader in your TypeScript code (.ts or .tsx)

// ES6 Modules
import typesTI from 'ts-interface-loader!./types'

// ES5 (CommonJS)
const typesTI = require('ts-interface-loader!./types')

Note: Using tsc or tslint? You'll need to add @ts-ignore and tslint:disable-line:no-implicit-dependencies for now, as there is no support (natively or through plugins) for supporting importing webpack loaders inline.

// @ts-ignore
import typesTI from 'ts-interface-loader!./types' // tslint:disable-line

Development

Clone the repository

$ git clone https://github.com/spotify/ts-interface-loader.git
$ cd ts-interface-loader/
$ yarn install

Run

# Get started
$ yarn build
$ cd example/
$ yarn watch

# Run some commands!
$ cat src/__fixtures__/ok-all-matching-types.json | yarn run --silent cli | jq '.manifestJson'
$ cat src/__fixtures__/error-no-tvshows-key.json | yarn run --silent cli | jq '.manifestValidator'
$ cat src/__fixtures__/error-no-tvshows-key.json | yarn run --silent cli | jq '.manifestStrictValidator'

# Take a look at other fixtures!
$ cd src/__fixtures__

Test

Run the following command

$ yarn test

Changelog

v1.0.2

Fixed security bugs with:

  • mixin-deep by bumping from 1.3.1 to 1.3.2
  • set-value by bumping from 2.0.0 to 2.0.1
  • serialize-javascript by bumping from 1.4.0 to 2.1.1

v1.0.1

Fixed security bug with handlebars by bumping from 4.1.2 to 4.5.3

v1.0.0

Initial release

Contributing

We strictly adhere to the Contributor Covenant in this repository, and wish to foster an open source culture that's welcoming and diverse.

Pull requests and stars are always welcome. For bugs and feature requests, please create an issue.

  1. Fork it!
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request :)