typescript-is
typescript-is copied to clipboard
Performance regression in 0.10
Input:
import { createIs } from 'typescript-is';
export const enum MyEnum {
Alpha = 'alpha',
Bravo = 'bravo',
Charlie = 'charlie',
Delta = 'delta',
Echo = 'echo',
Foxtrot = 'foxtrot',
Golf = 'golf',
Hotel = 'hotel',
India = 'india',
Juliet = 'juliet',
}
export const isMyEnum = createIs<MyEnum>();
typescript-is 0.9 output:
const isMyEnum = object => { return object === "alpha" || object === "bravo" || object === "charlie" || object === "delta" || object === "echo" || object === "foxtrot" || object === "golf" || object === "hotel" || object === "india" || object === "juliet"; };
export { isMyEnum };
typescript-is 0.10 output:
import { createIs } from 'typescript-is';
const isMyEnum = createIs(object => { var path = ["$"]; function _74(object) { if (object !== "alpha")
return "validation failed at " + path.join(".") + ": expected string 'alpha'";
else
return null; } function _76(object) { if (object !== "bravo")
return "validation failed at " + path.join(".") + ": expected string 'bravo'";
else
return null; } function _78(object) { if (object !== "charlie")
return "validation failed at " + path.join(".") + ": expected string 'charlie'";
else
return null; } function _80(object) { if (object !== "delta")
return "validation failed at " + path.join(".") + ": expected string 'delta'";
else
return null; } function _82(object) { if (object !== "echo")
return "validation failed at " + path.join(".") + ": expected string 'echo'";
else
return null; } function _84(object) { if (object !== "foxtrot")
return "validation failed at " + path.join(".") + ": expected string 'foxtrot'";
else
return null; } function _86(object) { if (object !== "golf")
return "validation failed at " + path.join(".") + ": expected string 'golf'";
else
return null; } function _88(object) { if (object !== "hotel")
return "validation failed at " + path.join(".") + ": expected string 'hotel'";
else
return null; } function _90(object) { if (object !== "india")
return "validation failed at " + path.join(".") + ": expected string 'india'";
else
return null; } function _92(object) { if (object !== "juliet")
return "validation failed at " + path.join(".") + ": expected string 'juliet'";
else
return null; } function _94(object) { var conditions = [_74, _76, _78, _80, _82, _84, _86, _88, _90, _92]; for (const condition of conditions) {
var error = condition(object);
if (!error)
return null;
} return "validation failed at " + path.join(".") + ": there are no valid alternatives"; } var error = _94(object); return error; });
export { isMyEnum };
typescript-is 0.11 seems to have the same output as typescript-is 0.10
Especially given that the output of the isMyEnum function is just a boolean, this seems extremely wasteful in the 0.10+ versions.
Here's a jsperf to illustrate this regression -- in v8 this code is ~1100x slower. Likely a good idea to revert this change, given that. Thanks all.
https://jsperf.com/typescript-is-changes-2
Hi @ckknight @Kingles
It's true that with the new generated the code there is a lot more complexity, becoming bigger in size and slower in run time performance.
The reason for it is so that the assert family of functions can have much better error reporting.
I agree that this is unnecessary for the is family of functions.
May I ask about your use-case? I'm just wondering if the performance hit is really noticeable at all (are we talking millions of validation calls per second?)
If necessary I can make the is family of functions output simple Boolean expressions again, but it will take some work because I don't want to maintain two copies of the code (one for generating is and one for generating assert code) and I will need to insert some layer of abstraction to keep the logic unified.
Thanks!
@woutervh- Let me join this conversation. We have some use cases when we need to validate 100k+ data members in one step. Note that so far we don't know if the overhead required by validation would make a significant impact - just wanted to let you know that such large datasets are valid requirements in some cases.
hi @hernyo
Thanks for the info. I will see if I can make some time for performance improvements for the is family of functions ;)
Hi, any chance this has been addressed? I checked through the release notes but didn't see anything mentioning it.
Thank you!
Hi @sarah-buhler
Unfortunately I haven't had the time yet to work on this, as it will take quite some time to complete. Does this have a big impact on your project? If so, I'll consider it higher on the list of things to do.
Hi @woutervh-
I made this comment while looking for a library for typeguarding and was still deciding on one at the time. I have been using your library for the past couple days and wrote a test for how quick validation actually occurs, and it seems just fine to me. In my test, 100k is<MyInterface>(Object) tests complete in less than 700ms. While previous releases might have run faster, I do not think the performance now is terrible or anything. My use case doesn't need nearly that many subsequent validations.
Now my problem is the fact that Date types in interfaces break everything at run time, which I thought would not be the case with both "ignoreClasses": true and "ignoreMethods": true in my tsconfig.json. I will be subsequently opening an issue on that now.
May I ask about your use-case? I'm just wondering if the performance hit is really noticeable at all (are we talking millions of validation calls per second?)
Just to add: a major use-case for typescript-is is when you're running a server and you want to verify that a user-submitted request object is valid. This library is awesome for that, because it saves having to write lots of tedious validation code.
Since the validation is occurring on the hot path (for every request!), there is value in it being fast.
It would be very neat if there was an transformer option (which we could toggle for development-vs-production) that changed the behaviour of the assert* functions to be "slow and helpful" or "fast".
A minimal solution would to be - as you have said - to make is stop being slow. I'm having to stick with the older version due to this slowdown.