TypeScript Simple Type Checker
ts-simple-type is a TypeScript utility library (current stable version 1.0.7, last published July 2020) designed to provide essential helper functions for analyzing and comparing TypeScript types. It aims to bridge gaps in the native TypeScript compiler API, particularly for direct assignability checks and programmatically constructing types, as noted by discussions in TypeScript GitHub issues #9879 and #29432. The library works by converting native TypeScript `ts.Type` objects into its own `SimpleType` interface, which offers a more standardized and easily serializable representation. This `SimpleType` abstraction facilitates advanced type analysis, comparison, and even serialization for use in various environments, including browsers. A key differentiator is its extensive test suite, comprising over 35,000 tests that validate its type-checking results against actual TypeScript diagnostics. Despite its usefulness, the package shows a slower release cadence, with the last update in 2020, suggesting it is now in a maintenance state rather than active development.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'kind') or Argument of type 'undefined' is not assignable to parameter of type 'SimpleTypeKind'.
cause Attempting to use a type function (e.g., `isAssignableToType`) without providing a valid `ts.Type` or `SimpleType` object, or an incorrect `SimpleType` structure.fixEnsure that the `ts.Type` or `SimpleType` arguments passed to functions like `isAssignableToType` are not `undefined` and conform to the expected interface, especially if constructing `SimpleType` objects manually. -
Error: Parameter 'typeChecker' is required when giving a Typescript Type to the function.
cause Functions like `isAssignableToType` and `toSimpleType` are called with a native `ts.Type` object but without providing a `ts.TypeChecker` instance.fixWhen working with `ts.Type` objects, always pass the `ts.TypeChecker` instance (obtained from `program.getTypeChecker()`) as the third argument to the `ts-simple-type` functions that require it. -
TS2304: Cannot find name 'ts'.
cause The `typescript` package is not imported or installed when attempting to use its API (e.g., `ts.createProgram`, `ts.ScriptTarget`).fixInstall `typescript` as a development dependency (`npm install typescript --save-dev`) and import it (`import ts from 'typescript';`) where its API is used, especially for setting up the `TypeChecker`.
Warnings
- breaking `toTypeString` function was renamed to `typeToString`.
- breaking `simpleTypeToString` is no longer exported.
- breaking The `spread` property on `SimpleTypeFunctionParameter` was renamed to `rest`.
- breaking The `hasRestElement` property on `SimpleTypeTuple` was renamed to `rest`.
- breaking `SimpleTypeKind` and `SimpleTypeModifierKind` were converted from enums to string literal unions.
- breaking The `methods` and `properties` properties on `SimpleTypeClass` were renamed to `members`.
Install
-
npm install ts-simple-type -
yarn add ts-simple-type -
pnpm add ts-simple-type
Imports
- isAssignableToType
const isAssignableToType = require('ts-simple-type').isAssignableToType;import { isAssignableToType } from 'ts-simple-type'; - toSimpleType
import toSimpleType from 'ts-simple-type';
import { toSimpleType } from 'ts-simple-type'; - SimpleType
import { Type } from 'ts-simple-type';import { SimpleType } from 'ts-simple-type'; - typeToString
import { typeToString } from 'ts-simple-type';
Quickstart
import ts from 'typescript';
import { isAssignableToType, toSimpleType, typeToString, SimpleType } from 'ts-simple-type';
// 1. Set up a minimal TypeScript program to get a TypeChecker
const code = `
type MyNumber = number;
let a: MyNumber = 10;
let b: string = "hello";
let d: string | number = 5;
`;
const fileName = 'test-file.ts';
const sourceFile = ts.createSourceFile(fileName, code, ts.ScriptTarget.ES2015, true);
const host: ts.LanguageServiceHost = {
getScriptFileNames: () => [fileName],
getScriptVersion: (f) => '1',
getScriptSnapshot: (f) => {
if (f === fileName) {
return ts.ScriptSnapshot.fromString(code);
}
return undefined;
},
getCurrentDirectory: () => '/',
getCompilationSettings: () => ({}),
getDefaultLibFileName: ts.getDefaultLibFileName,
fileExists: (f) => f === fileName,
readFile: (f) => (f === fileName ? code : undefined),
readDirectory: () => [],
};
const program = ts.createProgram([fileName], {}, host);
const typeChecker = program.getTypeChecker();
// 2. Extract TypeScript types from the AST
const typeAliases = sourceFile.statements.filter(ts.isTypeAliasDeclaration);
const varStatements = sourceFile.statements.filter(ts.isVariableStatement);
const myNumberType = typeChecker.getTypeFromTypeNode(typeAliases[0].type); // Type of 'MyNumber'
const aSymbol = typeChecker.getSymbolAtLocation(varStatements[0].declarationList.declarations[0].name);
const aType = aSymbol ? typeChecker.getTypeOfSymbolAtLocation(aSymbol, aSymbol.valueDeclaration!) : undefined; // Type of 'a'
const bSymbol = typeChecker.getSymbolAtLocation(varStatements[1].declarationList.declarations[0].name);
const bType = bSymbol ? typeChecker.getTypeOfSymbolAtLocation(bSymbol, bSymbol.valueDeclaration!) : undefined; // Type of 'b'
const dSymbol = typeChecker.getSymbolAtLocation(varStatements[2].declarationList.declarations[0].name);
const dType = dSymbol ? typeChecker.getTypeOfSymbolAtLocation(dSymbol, dSymbol.valueDeclaration!) : undefined; // Type of 'd'
if (aType && bType && dType) {
// 3. Use ts-simple-type to check assignability and convert types
console.log(`Is '${typeToString(toSimpleType(aType, typeChecker))}' assignable to 'number'? ${isAssignableToType(aType, myNumberType, typeChecker)}`); // true
console.log(`Is '${typeToString(toSimpleType(bType, typeChecker))}' assignable to 'number'? ${isAssignableToType(bType, myNumberType, typeChecker)}`); // false
console.log(`Is '${typeToString(toSimpleType(dType, typeChecker))}' assignable to 'number'? ${isAssignableToType(dType, myNumberType, typeChecker)}`); // true
// Demonstrate working with SimpleType directly
const customStringType: SimpleType = { kind: "STRING" };
const customNumberType: SimpleType = { kind: "NUMBER" };
console.log(`Is '${typeToString(toSimpleType(bType, typeChecker))}' assignable to custom STRING type? ${isAssignableToType(bType, customStringType, typeChecker)}`); // true
console.log(`Is '${typeToString(toSimpleType(aType, typeChecker))}' assignable to custom NUMBER type? ${isAssignableToType(aType, customNumberType, typeChecker)}`); // true
}