Skip to content

Instantly share code, notes, and snippets.

@fvilante
Created December 3, 2019 14:56
Show Gist options
  • Save fvilante/7e5b468b77e21fdc811969b2020ef131 to your computer and use it in GitHub Desktop.
Save fvilante/7e5b468b77e21fdc811969b2020ef131 to your computer and use it in GitHub Desktop.
Can Typescript perform run-time check at compile-time ?
// Here we will put the solution.
// But before let's have a talk bellow.
@fvilante
Copy link
Author

fvilante commented Dec 3, 2019

THE PROBLEM

"Does Typescript type check in runtime, ex: handling user input errors, or if API endpoint data shape changes or goes down?"

THE DISCUSSION OBJECTIVE

My intention is to prove that Typescript can perform equivalent "run-time type cheking" assisted by its static-type checker.
Therefore making it possible to alert at static-time things that otherwise should only be alterted at run-time.

ADVANTAGES OF THIS TECHNIQUE

  • Early bug detection
  • Fast development

METHOD OF DISCUSSION

I suggest we start by very basic building-block and then make it arbitrarly difficult. Probably about one to three study cases may be enought to catch the overall priciple. Discussion is open to everyone, and I suposed that if I'm wrong you'll help me to see it.

Here we go...

@fvilante
Copy link
Author

fvilante commented Dec 3, 2019

STUDY CASE 01

PREVENTING WRONG USE OF FUNCTIONS

Let's imagine we have two functions, I will call it arbitrarily f and g, and they receive different types of arguments, lets say number and string but both of them returns same type which is a number.

You decided to use this functions as mapper functions to arrays, but you don't want to use the wrong function to map the correct array.

const f = a_string => 2        // note: sorry the strange syntax, it is just a function (nothing more than that).
const g = a_number => 3

const a = [1,1,1]                   // just an arbitrary array of numbers. Not more than that.
// const strings = ['z','z','z']      // omited for simplicity

const r0 = a.map(g) // ok!
const r1 = a.map(f)  // BAD ERROR!!  you are mapping the array of number with the wrong function !

QUESTION

How do you write your code using JS to CATCH this kind of BAD ERRORS admitting that it CAN occur at RUN-TIME.

Note that we can substitute Array by a Promise, and map to then, and every coinclusion bellow still the same. There is a very general concept playing here on the background.

Example seems very simple, but image that 'f' and 'g' should be your whole program with thousands of lines inside the function (or method). The principe playing here is the same: something in, something out. I'm just reducing the problem to its lowerst-denominator. Other examples may help we get an 'aha-moment'.

@fvilante
Copy link
Author

fvilante commented Dec 3, 2019

JAVASCRIPT SOLUTION

I do not know other way in JS to DETECT this kind of error. Here is my solution:

const f = a_string => { 
    if (typeof(a_string) === 'string') 
        return 2 
    else
        throw Error('Error! input it is not a string') 
}

const g = a_number => { 
     if (typeof(a_number ) === 'number') 
        return 3 
    else
        throw Error('Error! Input it is not a number') 
}

const a = [1,1,1]
 
const r0 = a.map(g) // OK
const r1 = a.map(f)  // BAD but we'll CATCH that error at run-time with a beaultfull message.

SOLUTION CONSIDERATIONS

Ok, now at cost of some additional lines we have a "run-time error detection" mechanism that can stop our program execution if it's making a previsible mistake.

@fvilante
Copy link
Author

fvilante commented Dec 3, 2019

TYPESCRIPT SOLUTION

ERROR MESSAGE

Here is the error that bellow code produces at static-time in Typescript Playgound:

Argument of type '(_: string) => number' is not assignable to ...
   Type 'number' is not assignable to type 'string'.(2345)

SOLUTION CODE

The code bellow is: informative, shorter at development and at run-time, and just has what is necessary to solve the proposed problem:

const f = (_:string) => 2        // note: sorry the strange syntax, it is just a function (nothing more than that).
const g = (_:number) => 3

const a = [1,1,1]
// const s = ['z','z','z'] , etc...

const r0 = a.map(g) // ok!
const r1 = a.map(f)   // BAD ERROR!! But we know that at exactly moment we typed it. we cannot proceed until you solve that.

JAVSCRIPT TRANSPILATED CODE

Look that the Typescript output code is exactly equals the initial problem. No "run-time error detection code" will be generated or necessary.

"use strict";
const f = (_) => 2; // note: sorry the strange syntax, it is just a function (nothing more than that).
const g = (_) => 3;
const a = [1, 1, 1];
// const s = ['z','z','z'] , etc...
const r0 = a.map(g); // ok!
const r1 = a.map(f); // BAD ERROR!! But we know that at exactly moment we typed it. we cannot proceed until you solve that.

@fvilante
Copy link
Author

fvilante commented Dec 3, 2019

STUDY CASE 01 - CONCLUSION

Original answer:

Does Typescript type check in runtime ?

Response:

yes, in the sense that it avoids runtime checks bring the effect that they generate to static-time.

WHAT MORE ?

Can this technique be generalized ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment