Compile TypeScript Types for runtime use
I have a client server application that communicates using REST calls.
To prevent that I accedently use the wrong types I defined all RestCalls in a common file (excerpt):
type def<TConnection extends Connections> =
// Authentication
TConnection extends '/auth/password/check/:login->get' ? Set<void, { found: boolean }, void, false>
: TConnection extends '/auth/password/register->post' ? Set<RegsiterAccount<Login>, void, void, false>
: TConnection extends '/auth/password/login->post' ? Set<Login, void, void, false>
: TConnection extends '/auth/webauth/challenge->get' ? Set<void, {
challenge: string,
id: string
}, void, false>
: TConnection extends '/auth/webauth/register->post' ? Set<RegsiterAccount<WebAuthN> & { comment: string }, void, void, false>
: TConnection extends '/auth/webauth/login->post' ? Set<Assertion, void, void, false>
: TConnection extends '/auth/logout->post' ? Set<void, void, void>
: TConnection extends '/auth/invite->get' ? Set<void, {
link: string,
validUntill: string
}, void>
: TConnection extends '/auth/invite/validate->post' ? Set<{ invite: string }, {
granted_by: string,
validUntill: string
}, void, false>
: TConnection extends '/auth/isAuthenticated->get' ? Set<void, {
isAuthenticated: boolean,
userName: string | undefined
}, void, false>
// default
: never
The url and method are encoded in the string, it also uses express url parameters (/:
).
Set
defines the data in the body and if the server should check authentication
- request
- response
- response on error
- if authentication is needed
type Set<Input extends (Object | void), result extends (Object | void), Error extends string | object | void, NeedsAuthentication extends boolean = true> = {
input: Input, result: result,
error: DefaultError<Error>,
authenticated: NeedsAuthentication
};
I can then use following types to get the correct values
export type InputBody<TPath extends Connections> = def<TPath>['input'];
export type InputPath<TPath extends Connections> = express.RouteParameters<TPath>;
export type Input<TPath extends Connections> = InputBody<TPath> & InputPath<TPath>;
export type Result<TPath extends Connections> = def<TPath>['result']
export type NeedsAuthentication<TPath extends Connections> = def<TPath>['authenticated']
export type Error<TPath extends Connections> = def<TPath>['error']
export type Method<T extends string> = T extends `${infer path}->${infer method}`
? method extends METHODS ? method
: never
: never;
export type Path<T extends string> = T extends `${infer path}->${infer method}`
? method extends METHODS ? path
: never
: never;
I would now like to know at runtime if for a specific call authentication is required.
I could encode it in the url like I did for the method. Or use NeedsAuthentication
as a paramter where the url is also provided. That way when I put in the URL I get autocomplete for that will only have true if authentication is needed otherwise false.
I don't like both workarounds.
What I would like to do is
const needsAuthentication :boolean = NeedsAuthentication<'/auth/webauth/login->post'>;
Is there any way to tell the compiler to compile the types in the output JS so I cann do the same thing the compiler does when interfereing what a parameter needs to be?
My only other solution currently is writing a script that is executed prebuild which parses my definition and put out a map that contains for every URL if it needs authentication using some regex parsing...
EDIT
I would like to implement following function
function needsAuthentication<T extends Connections>(test:T):NeedsAuthentication<T> {
// todo find out if authentication is actual required for this url
}
which is not part of the transmited data but encoded in the type mapping.
The compiler will nicely map it to true or false for const strings on compieltime (the actual value would still not be emiited...)
I could try to use the typescript compiler and call whatever function evaluates the return values...
Solution 1:
No. Typescript types will be emitted during the compilation phase.
Your options are:
- Use JSON-Schema (Ajv) to validat the input of incoming http json requests: https://github.com/ajv-validator/ajv
- Use Swagger (Almost the same as (1)).
- Use a validator which works with your framework.
- I found this project which tries to create runtime asserts from typescript types: https://github.com/skunkteam/types. But I never used it my self.
- https://github.com/nanoporetech/ts-runtime-typecheck - Same as (4) but never used it as well.