We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Strong Dynamic Type Checking for JavaScript

00:00

Formal Metadata

Title
Strong Dynamic Type Checking for JavaScript
Subtitle
Where TypeScript is helpless, JavaScript Proxies come to the rescue!
Title of Series
Number of Parts
542
Author
License
CC Attribution 2.0 Belgium:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
JavaScript developers learned to love TypeScript after seeing the benefits of static type-checking. But there is still a lot of data that that TypeScript is not able to check, because it is only known at runtime: JSON responses from an API, user inputs in a form, content taken from client-side local storages, browsers API quirks... In that case, you can only assume the types and pray for the best, or manually code tedious specific type checks. I'd like to introduce you to ObjectModel, an open source library I created with the intent to bring automatic strong dynamic type-checking to JavaScript projects. By leveraging ES6 Proxies, this library ensures that your variables always match the model definition and validation constraints you added to them. Thanks to the generated exceptions, it will help you spot potential bugs and save you time spent on debugging. I will also discuss the many other benefits of validating types at runtime, because as you will see, it leads to more than just type checking. I will present a few scenarios where TypeScript is helpless to detect type errors. Then I will discuss about ES6 Proxies, and how you can make type-safe objects in JavaScript itself. Finally I will present ObjectModel, a mature, well tested open source library that has ~2500 weekly downloads on NPM. ObjectModel is very easy to master: no new language to learn, no new tools, no compilation step, just a minimalist and intuitive API in a plain old JS micro-library. The audience should be able to immediately understand the interest of this library regarding the type assertions, but as a conclusion I will show how ObjectModel can also be used for other usecases such as form validation or API unit testing.
14
15
43
87
Thumbnail
26:29
146
Thumbnail
18:05
199
207
Thumbnail
22:17
264
278
Thumbnail
30:52
293
Thumbnail
15:53
341
Thumbnail
31:01
354
359
410
Quantum chromodynamicsRule of inferenceWechselseitige InformationScripting languageJava appletVariable (mathematics)Open sourceComputer wormFluid staticsInterface (computing)TypprüfungCapability Maturity ModelSoftware developerLocal area networkGEDCOMCompilerWorld Wide Web ConsortiumTwin primeInferenceCodeCompilerElectronic mailing listBootingDefault (computer science)ParsingParallel portInformationMereologyMedical imagingParameter (computer programming)Library (computing)Compilation albumNatural numberSoftware developerCompilerWeightMultiplication signProcess (computing)Bookmark (World Wide Web)Web-DesignerPoint (geometry)Web applicationTypsichere SpracheComputer programmingResultantFluid staticsElement (mathematics)Axiom of choiceProjective planeIntegrated development environmentCodeRight angleVariable (mathematics)Quantum chromodynamics2 (number)Operator (mathematics)TypinferenzProgramming languageReference dataString (computer science)NumberFront and back endsBitInsertion lossKeyboard shortcutCartesian coordinate systemRule of inferencePotenz <Mathematik>CASE <Informatik>Computer filePredictabilityInternet service providerWeb 2.0Computer animation
Scripting languageWeb browserServer (computing)Dependent and independent variablesClient (computing)CompilerError messageVariable (mathematics)Run time (program lifecycle phase)Home pageRepository (publishing)CodeDynamical systemJava appletStandard ModelObject-oriented programmingCore dumpObject modelLibrary (computing)Element (mathematics)Revision controlPhase transitionOrder (biology)String (computer science)NumberProduct (business)Boolean algebraException handlingRun time (program lifecycle phase)Data loggerMultiplication signNumberConstructor (object-oriented programming)Category of beingCartesian coordinate systemTypsichere SpracheDifferent (Kate Ryan album)Product (business)Error messageConnectivity (graph theory)Quantum chromodynamicsReal numberStandard ModelLibrary (computing)Functional (mathematics)Object-oriented programmingException handlingDependent and independent variablesFile systemVideo gameCloud computingProjective planeMessage passingRevision controlProcess (computing)InformationOrder (biology)Software developerForm (programming)Validity (statistics)Open sourceKeyboard shortcutObject modelLogicCompilerService (economics)String (computer science)Cache (computing)Web 2.0CASE <Informatik>Web browserEmailServer (computing)DatabaseStandard deviationQuery languageSoftware bugRegular graphView (database)PrototypeLevel (video gaming)TypprüfungMereologyPattern languagePoint (geometry)Computer animation
Standard ModelObject (grammar)Complex (psychology)LogicError messageMessage passingProcess (computing)Continuous functionWeb browserGraphical user interfaceData managementProxy serverNatural numberRegulärer Ausdruck <Textverarbeitung>Parameter (computer programming)Run time (program lifecycle phase)Functional (mathematics)Generic programmingStandard ModelLibrary (computing)Object (grammar)Variable (mathematics)MereologyGame controllerValidity (statistics)Constructor (object-oriented programming)Different (Kate Ryan album)WordAttribute grammarCategory of beingObject modelError messageTypprüfungOperator (mathematics)Analytic continuationProcess (computing)Software developerCASE <Informatik>Covering spaceLogicMultiplication signSocial classStrategy gameComplex (psychology)String (computer science)NumberRevision controlCartesian coordinate systemFluid staticsDescriptive statisticsService (economics)IntegerCache (computing)Typsichere SpracheBitComputer animation
Message passingError messageProcess (computing)Continuous functionWeb browserGraphical user interfaceData managementQuantum chromodynamicsAddress spaceLocal ringData storage deviceInterface (computing)LogicCore dumpStandard ModelComputer networkObject modelRun time (program lifecycle phase)LogicLibrary (computing)Cartesian coordinate systemCore dumpMultiplication signMereologyElectric generatorProcess (computing)Projective planeSoftware developerCodeObject modelSpacetimeWeb browseroutputDifferent (Kate Ryan album)CASE <Informatik>Standard ModelProxy serverPresentation of a groupValidity (statistics)Sinc functionMathematicsData structureBitQuantum chromodynamicsData storage deviceInterface (computing)Vector potentialData conversionComputer animation
Multiplication signSoftwareRun time (program lifecycle phase)Validity (statistics)Standard ModelProxy serverFunctional (mathematics)Product (business)Mathematical optimizationSubsetDatabase transactionInterface (computing)Point (geometry)HookingInsertion lossFraction (mathematics)Declarative programmingGame controllerObject model
Program flowchart
Transcript: English(auto-generated)
All right, can you hear me in the back? Yeah, okay, perfect. So
Thank you for being here. I was not expecting such a large room of JavaScript developers and nothing has been broken yet So it's unbelievable So yeah, I'm here to talk about strong dynamic type checking for JavaScript Which may sound a bit weird because you are not expecting strong type checking and JavaScript in the same sentence, right?
But I will prove that we can do something about it So first, what is strong type checking? What do we mean by that? So let's do a bit of vocabulary So I try to find one definition online of what is strong type checking and couldn't find any It's like a never-ending argument about which one which language is strong and which one isn't
But I found two definitions commonly accepted The first one is that this strong type checking means that you have this kind of explicit binding Between some variable name and some type So this variable and this type are like bound together That means that every time you are calling variable by its name
You will get some reference data that matches the type you expect the second definition is More regarding the program language features like no lack of type safety due to loser typing rules For example for the case of JavaScript we have implicit type correction That means that it's perfectly fine to get the plus operator between a number and a string for JavaScript is just string concatenation and
Automatically casting the number to a string but for other languages like Python you will get a type error So that's taken as an example to show that Python is more strong stronger than JavaScript
So when it comes to JavaScript, whatever definition you pick you might say that JavaScript is not a strongly typed language and you will be right Because JavaScript is based on dynamic type checking, you got dynamic typing That means that JavaScript variables you can assign it to some type and then move to another type and go on
It doesn't matter So because types can change during program execution that makes types in JavaScript quite unpredictable So the creator of the language, Pandan H, justified his choice by saying that Developers can be more expressive when you got dynamic typing which means that can get to the result faster But he also agrees that it is also more error prone. So that's the image I took for this
Static versus dynamic typing. I think it's a pretty well So yeah, JavaScript and strong type checking not really actually every time you see someone complaining about JavaScript or mocking JavaScript It would be about one of these memes, right?
So these are some of my favorites maybe you know others But as you can see almost all these jokes about JavaScript are basically about the lack of strong type checking Which is too bad So some people will decide to just get rid of JavaScript and maybe go to a Kotlin or .NET or
Whatever language we have seen this morning But I think that's the most common solution to this approach has been TypeScript, right? I mean this thing has been invented specially to address this issue by having some optional static type checking About JavaScript. So how many of you are using TypeScript raise your hand? Wow
I was expecting that like almost 100% of these people in this room are using TypeScript I mean, why wouldn't we use TypeScript? It's so popular almost all the ecosystem of the libraries today on the NPM Ecosystem have been converted to TypeScript or provide TypeScript definition files
So we have seen this kind of exponential growth in popularity among the years. TypeScript is 10 years now It would be 11 in 5 days actually and it has never been so popular So did we solve the issue of type checking JavaScript with TypeScript? I would say not entirely and I explain why
Here are some things I learned about TypeScript after 10 years The first one is a bit of shock is that type checking is not actually the main selling point of TypeScript The main selling point of TypeScript is developer experience So if you have practiced TypeScript and the whole room has done that so it's great
You have seen some improvements in your development experience So many things like be able to export some API by using the auto complete Be able to detect some typos that you have done in your code be able to refactor your code more easily Thanks to the static type annotations
Maybe have some documentation right inside your IDE Some compilers are using static type annotations to bring some compile time optimizations, which is great You get type inference, great type inference in TypeScript So we don't have to write all the static type annotations at any time And we have seen some innovative use of TypeScript
For example, the Angular community is using a lot of TypeScript annotations to make some code generation, which is great So all of this is part of developer experience and it's great, but it's not really about type checking anymore It's much more than that I figured out that type checking was not the main selling point of TypeScript, or at least not anymore
When I looked at the esbuild project, one of the most important JavaScript projects of these last years esbuild, the famous bundler So maybe you are using the vite development server, some people in the room So vite is based on esbuild And does esbuild support TypeScript? Of course it does, everyone is using TypeScript
But the fact is that esbuild does not actually do any type checking when it compiles some TypeScript code All it does is look at the TypeScript code, look at the TypeScript part, the static type annotations, and just get rid of it That's all it does, nothing else And they say that running the whole TypeScript compiler is actually a loss of time today
Because of this development experience, developers have this whole integrated type safe environment and development process So that means that you don't need to do it twice a second time on compilation The second point of TypeScript that I learned about 10 years later
is that type safety in TypeScript can be easily defeated What I mean by that is that in many scenarios in your application, you are relying on type assertions That is, these little elements like the ASCII word, or the exclamation mark here Which is, I ensure the compiler that is not null
So all these things are not bringing any type safety, it's just the developer saying to the compiler Trust me, I know what I'm doing And most of the time, we do not So yeah, this problem, these type of sections, you can find them easily on any web application There are actually many parts where you are forced to use these kind of assertions
Because of the nature of the web You can have your perfectly type safe TypeScript application And still have to deal with lots of unpredictability Unpredictable is like, most of the time, your job for a front-end web developer And what I mean by unpredictable, it is known at runtime
That means it changes every time, at every user, and so on So for example, your application may have some backend services May call some APIs, maybe some third-party cloud providers And you are trusting the responses of these servers You are not validating any of the response of the server from the application side
So this could break You are also relying on a browser And some browsers have bugs and queries They do not fully support the JavaScript APIs, the web standard APIs I chose this logo for a reason, why? You may also have some client-side stored data for your application
Maybe you are storing on a local storage, some user preferences Or some file storage used as cache So this is likely to break as well Because sometimes the cache is outdated It comes from an older version of your application Or maybe it has been modified by the user itself, who knows?
And finally, maybe the most unpredictable part of every developer's job Did you guess it? The user The user can be very unpredictable If you have some application in production And have a look at the production database You will always find some crazy stuff like How did it get there? I don't understand
This is the user So yeah, all these things need to be validated Otherwise this is a recipe for disaster And can break your perfectly safe application in TypeScript So If you look at TypeScript and wonder How can I do that? How can I type check all of these things?
No luck, it's not a compiler problem Because all these things happen at runtime Right? You cannot anticipate it So it's more an applicative problem and not a compiler problem Which means that TypeScript is completely helpless And it is up to you, the developer, to find a solution to these problems
So how do we deal with runtime errors? Most of the time, the truth is that often we don't Maybe in the best of scenarios You are doing some custom logic to validate the data And trying to fix the stuff the best you can But most of the time you have so many different possible runtime errors
That you would have like try-catch blocks And trying to show some error messages to the user Saying them to call you and send us an email in case something bad happens And I also saw that we have some kind of global unexpected exception handler That is just sending all the runtime errors that you didn't catch
To maybe a monitoring service And it is added to a log file that you are checking like once in a month Looking at a bunch of errors and saying it's not worth my time So I should move to something else I don't know if some of you do that, but it happens, right? So it's too bad because we could figure a way to solve all these runtime errors
So back to this idea of strong dynamic type checking How can we do that? So I'm just sticking to the definition of a strong binding between variable name and a time here What if we could do this kind of strong binding but at runtime? What would it mean?
First it would mean that the type errors that we get would still be runtime errors Right? Because they are at runtime But at least they will be more explicit and more catch early That means that instead of having like undefined is not a function You will get an error message like this variable has been found undefined and it was not supposed to So instead of pointing to the consequences, it points to the source of the problem
So that helps a lot to reduce the investigation job that you have to do as a developer when doing debugging The second thing is that this strong binding should not be just a one-time validation pass I'm sure that there are plenty of JavaScript libraries that do that
That is, you are throwing a bunch of data to it and it validates saying true or false or just throwing a type error But we need more than that We actually need to have this binding that means the type information needs to live along with your data So it should be validated, this type checking thing, on every reassignment or mutation of this data
And finally the goal of this is to get rid of maybe some silent errors Because we have many mistakes in JavaScript that just are silent That is, you are not noticing them until it's too late And it can also make runtime errors maybe more predictable And so more manageable from a developer's point of view
So this is the main reasoning I have when I worked on the open source library That I want to present to you today, which is object model So definitely not a new project Actually, I've been working on this for the past eight years So I'm at the version of 4.4.1
That means that I have rewritten the entire thing like four times now It's obviously the hardest thing I had to code in my life I would say It's very complicated But it works So I'm glad And I would say also that it is my most used for real open source project
By used for real I mean that it is used in business projects So I use it in my professional projects Other people are using it as a fundamental component of their business project And I receive lots of positive feedback about this library You got an example here So what is this library doing?
So how do you use it? It's pretty simple actually The first thing you have to do is define the dynamic types I would say I would call them models I explain the difference later But basically it's that Let's say you are working on e-commerce application You can declare an object model for the order For example the customer order
Saying that you have a product which has a name property which is a string A quantity that is a number And also an order date After having declared this model You can now bind it to some data So this is where you have this strong binding between the type and the variable Here I used the constructor pattern
So that means you are calling new order I think it's probably the most intuitive form of a binding for the developer And also it helps to store the type information on the prototype level of the object So that's how I have this strong binding We already have a binding between object and prototypes in JavaScript And after having done that
You get the myorder object Which you can manipulate just like you would do with a regular JavaScript object But instead when you are assigning for example quantity to boolean instead of a number You will get a dynamic type error at runtime With an explicit message saying Expecting product quantity to be number and got boolean false instead
So because this happens Every time you are doing any mutation on an object It is really easy to quickly find some mistake that you are doing as a developer And so improve the debugging experience So that's great but how does it work? So let's start from a pretty basic example
Here I have a class user Having a constructor taking a name and an age And if you want to validate the parameters that are passed to a function And not rely on static type annotation in TypeScript That means that you will validate this data at runtime Maybe this data comes from an API for example
What you could do is use these if conditions And check the type of these different variables And throw type errors like that Pretty easy The problem with that is that it only works in the constructor So maybe you could decide to declare some setters Like set name, set age And had this validation process on every single attribute But it's a bit tedious and we can do better on that
So we can improve this by using a feature of JavaScript Which is the proxy So I don't know if everyone knows about proxies This is a feature of JavaScript that has been introduced in 2015 As part of ECMAScript 6 And proxies are actually really great feature
Really powerful The way proxy works is that they enable you to intercept Some operations that are done on some object And react to these operations So in this example I just use the set trap of the proxy Which means that every time I am reassigning a property I can execute some custom logic
So I can move my if type of name and different string and so on Into the set trap and be able to detect the different issues So that's great Now it works both for the constructor and the future reassignment The future mutations
What we can do as a first step Is try to make a generic function out of this Like so So now I just move the definition part On this generic type check function argument So the type check function take two arguments First is the data Second one is the definition or the type issue prefer
So it makes clear that you have this strong binding between objects and types And as you can see it is really easy to make a generic function to do this kind of stuff So the type check function that you see here Is a very basic version of what object model is Of course the library is much more complicated than that
It can cover many other use cases But you get the idea with this example So as you can see it is really easy to reuse this type check function To apply to it to many different models So why did I call these models and not types? Actually I wanted to find another word just to make a straight
That there is a few differences from the types that you know from TypeScript for example Because everything happens at runtime This is runtime data validations That means that models are more powerful than just the static types For example they can not only check the types but also the values Let's say I have a short model
Which can have a size which is either a number or a letter Like M, S, L, XL and so on I could decide to have this kind of type annotation To have both control that it is either a number or the letter M Or a string matching this regular expression I can also have some more complex assumptions
For example if I want integers in JavaScript Yeah integers in JavaScript So it will be still number in the end Because that's how JavaScript handles numbers It's a double 64 bits But I can add another assertion on this number model To say I need to check that it is an integer And maybe if I want it to be a positive integer
I can add another assertion to make sure that it's above zero So this is the kind of stuff of assertions that you can have And again every time you are manipulating this property For example the age of the user It will check all these assertions automatically And also the last difference from models to types
Is that model validation can affect application logic Because it's happening at runtime That means you need to react to it And have some strategies of how to handle these runtime errors For example if you got some error Some type error on your short model Maybe you just want to cancel the order So that you are actually making sure that Everything is happening correctly on your application
So these are the main differences So to get a look at the pros and cons of this library First the pros You get descriptive error messages They are pointing to the initial problem And not the consequences So just that saves you a lot of time
And it means that you now have this kind of continuous data validation As part of your development process That means you get faster debugging And more reliable applications in the end Regarding how you manage these runtime errors Because you need to do something right Not only showing an error message But maybe doing some strategies that are planned
You can define some global or maybe per feature Per model strategies about how to manage these errors Maybe some errors can be easily manageable For example clean up an outdated cache Or maybe some of them are more complex And then you need to maybe log them into a monitoring service
Some of the cons of this library One about performance of course Because since it's happening at runtime That means that it has a performance cost Don't worry it's not too much But if you are doing some heavy mutations Like more than 100 times per second Maybe you should avoid using dynamic time shaking For this specific scenario But most of the times you don't have to do this
So it's great The second problem is that it relies on proxies So you need support for it Today modern browsers are supporting ES6 proxies But if you have older browsers for some users This can be an issue
So which is better? Static time shaking or dynamic time shaking? The correct answer is you should use both Because they address different issues TypeScript we saw it It's awesome It improves a lot with the developer experience It makes you have a coding base which is reliable And makes sense which is logical But you should also take care of all the unpredictable parts
That are happening at the runtime of your application So my personal recommendation would be to Stick to TypeScript for the core application logic But also add this object model layer For every external interface that you have to deal with Like this server, the user inputs The local stores or the browser APIs
And this can lead to a more reliable application That's all I have for you today So thank you for listening And I'm taking questions Thank you very much So we have time for questions
Who would like to ask the first question? My question is Have you ever tried using this library with other libraries
For like as it's called Immutable data or YAP for other validation? So we actually don't hear you properly Have you tried using this library with other libraries For dynamic checking like YAP
Or for immutable data like IMR or other libraries? Yeah, so immutable should work fine For other validation libraries I mean it's kind of the same thing The same job So maybe it doesn't work that well And doesn't make really a sense But I think it should work Exactly with immutable data structures So IMR should work fine
Do you think it would be possible To generate the object model definitions I don't know what to call them
Object models from TypeScript Okay that's a good question So actually you can do the opposite That means that if you are using models It will generate TypeScript types for you But because this is more than TypeScript And as you saw this can affect application logic That means that we cannot do this simple conversion If you use it dynamic TypeScript Just like you would do with TypeScript types
You are just using like 10% of the potential of the library And it wouldn't make any sense to me So you should see the website Maybe to have more examples of that But yeah it's a little bit more than that Yeah I see hands You were there The next speaker also
Could you raise your hand or stand up Okay so we'll have to contact them A fantastic idea Love the library So you mentioned rewriting it four times over eight years How stable would you consider the project to be? How often do breaking changes to the API get introduced?
That kind of thing Yeah it's true that I rewritten it four times But the API never changed That's one thing And also I use it for professional projects So I would be embarrassed if I had to throw it away All right So it's quite stable for many years now
Hello thank you for the presentation And I would like to know whether Would you recommend using object model on projects that has not yet TypeScript Only JavaScript Thank you
Yeah I mean that could be a thing Although if you are into strong type checking You're probably already using TypeScript If it's not the case maybe it's fine I don't know But yeah it's totally possible But most of people are using TypeScript Thank you very much We have time still if you have time
For another question Yeah You'll have to be loud because people are moving And if you sit down please make sure there is no space Because the room is pretty full Hi thank you for your project So one other approach is using for example JSON schemas
That then translates to types Should I speak? One other approach is using JSON schemas For example on the validation side Let's say in a controller And the JSON schema then compiles to the
Or deduces the TypeScript type that the schema defined So that's one way for example to do validation And not have a runtime penalty besides doing the validation itself Have you considered this approach for your use case?
Yes good question So you can indeed use this kind of type declaration One problem is that Again if you are sticking to what can TypeScript do with static type checking You are only just using a fraction of what can be done
For example I told you about custom transactions I told you about the fact that you can check values Along with the types So all of these things would not match the model that you are describing with JSON So that means we need to have another API for that And that's why I have the own API for object model Another last question
And then please everybody squeeze no empty seat There are a lot of people still standing So JavaScript is executed with v8 And there is a lot of optimization underneath Where like you have a inlining going on Optimization of the function
When you use proxies all of that is going to be gone immediately Like the performance it is not only when you set something And when you would normally go through the proxy It's not a hook how's it called again forgot the name Anyhow like when you have the trigger for it
But also for anything that relies upon that data from that point on So it's going to be a huge performance I would definitely not recommend it and it's pretty much in production Yeah I talk about the performance issues One thing is that it's only useful for applying to external interfaces
Like network requests You can just validate everything related to one request So the loss of time due to the network request Compared to the loss of time due to proxy It's acceptable in my opinion You can debate after don't worry and he's gone I mean I run a bunch of transactions and it takes less than two milliseconds
So I don't think the loss of time is so much trouble Thank you very much Thanks again