I am wondering if I can somehow extend or hook up to the TypeScript compiler and generate some functions based on the declaration of the TypeScript interfaces in my code. Basically these functions would validate the data objects that are coming from the server to comply with the TypeScript interfaces the objects are supposed to implement. I was thinking to have a special interface-marker and I wish my hook to the compiler was triggered by such interface. Once that marker-interface is detected I would analyze the members of that interface and generate the code that would validate a given object against the data-contract defined by that interface. Is there a way to do that? Can anyone give some directions?
The TypeScript compiler compiles these files and outputs the JavaScript with . js extension by keeping the same file name as the individual input file. The TypeScript compiler also preserves the original file path, hence the . js output file will be generated where the input file was in the directory structure.
Any valid JavaScript is also valid TypeScript. This means that you can write literal JS in any place in your code.
The TypeScript compiler supports a mix of JavaScript and TypeScript files if we use the compiler option --allowJs : TypeScript files are compiled. JavaScript files are simply copied over to the output directory (after a few simple type checks).
Short answer
Yes (thanks to TypeScript transformers), and there already exists a tool like that called typescript-is.
Long answer
A transformer is a function for which the AST of your program is exposed. A basic example:
import * as ts from 'typescript';
export default (program: ts.Program) => {
return (ctx: ts.TransformationContext) => {
return (sourceFile: ts.SourceFile) => {
function visitor(node: ts.Node): ts.Node {
/**
* If that's the kind of node you were looking for,
* do something with it and return it. Otherwise:
*/
return ts.visitEachChild(node, visitor, ctx);
}
return ts.visitEachChild(sourceFile, visitor, ctx);
};
};
}
Such a transformer can be used programmatically. If you would rather make it a standalone plugin used in your tsconfig.json
, you will need a wrapper for the TypeScript compiler that supports that, because TypeScript doesn't support plugins out of the box yet. ttypescript is an example of such a wrapper.
This seems like an interesting idea. I think you'd probably end up needing to modify the compiler code to do this; standard "tsc" doesn't export type information, other than the --declaration command line option, which I don't think does what you want.
You might start by looking at some code that has done a programmatic integration with the TS compiler. For instance, the grunt type script module: https://github.com/k-maru/grunt-typescript/blob/master/src/modules/compiler.ts
Still, this seems like a non-trivial problem. One way is to create TS code that references one of your data objects and tries to compile it to see if that data conforms to an interface. If you end up having to use the compiler itself to do this validation, you would probably find that its too slow for real time use.
Or, if you generate code yourself based on your marker interfaces, you might end up reimplementing a lot of the compiler, since the type system can get pretty complex (generics, function declarations, and structural subobjects come to mind)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With