-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"Probably the most advanced TypeScript runtime reflection system" #31
Comments
Hi @marcj, welcome to my humble repository. I just don't get one thing. You have focus on bundle size and you want to create eg. C++ interpreter for that. How would it run in the browser? WebAssembly? Cuz if it is meant for servers, size of generated metadata is not important IMHO.
Well, according to your text, this reflection system is level 3, which is ,,Advanced reflection". Your words. Size of generated metadata is something which can be easily changed. I'm designing plugin/middleware system for the transformer. Transformer creates JS objects with metadata (like it does now) and middleware can easily convert those metadata to anything (eg. bytecode). Runtime will parse that and we are good to go. Transformer does the same thing. Runtime does the same thing. Only metadata would be "compressed" somehow. My "advanced" means exactly what the Features section in the README says.
That sounds pretty advanced to me. I'd love to group the authors of all the reflection systems together. Create just the plain Reflection system standard. Type guards, validators, schemas,.. it is not Reflection. These are just things implemented via Reflection. My system is plain Reflection and anybody can build all the mentioned things on top of this system. Out of the box. End-developers don't have to change a single line of code. Just enable reflection system, install packages they want and use it. |
It runs in any JS environment, just like yours.
Only to a certain extend. If you want minimum rtti size, you need either a decompressor or bytecode interpreter, as outlined in the referenced issue. Additional emitted JS size related to type information is important especially in bigger projects.
Yes, the described level 3 is more than tst-reflect, as tst-reflect does not emit type functions, only the results, hence no dynamic type computation possible, which is required for resolving union generics in addition to extensive
You can't, see for example: function infer<T extends string|number>(v: T): Type
{
return getType<T>();
}
console.log(infer('abc'));
console.log(infer(23));
//or
function infer<T extends string|number>(v: T): Type
{
class A {
b!: T
}
return getType<A>();
}
console.log(infer('abc').getProperties()[0].type); do not work. A few other things that do not work while playing around with the code: //prints warning and returns undefined
type test<A extends 0[] = []> = `${A['length']}`;
console.log(getType<test>());
type StringToNum<T extends string, A extends 0[] = []> = `${A['length']}` extends T ? A['length'] : StringToNum<T, [...A, 0]>;
console.log(getType<StringToNum<'100'>>()); //small example from MongoDB filter structure
type RegExpForString<T> = T extends string ? (RegExp | T) : T;
type MongoAltQuery<T> = T extends Array<infer U> ? (T | RegExpForString<U>) : RegExpForString<T>;
type QuerySelector<T> = {
$eq?: T;
$not?: QuerySelector<T>;
}
type FilterQuery<T> = {
[P in keyof T]?: QuerySelector<T[P]>;
};
interface Product {
id: number;
title: string;
}
//getProperties()[1] is reported to be an union, which is wrong
const type = getType<QuerySelector<Product>>();
//other basic types are not support on getType()
console.log(getType<[string, number]>());
console.log(getType<[a: string, b: number]>());
console.log(getType<[string, ...number[]]>());
//no template literal support
console.log(getType<`a${number}`>());
//no literal support
console.log(getType<'abc'>()); //basic assignable not supported
interface A {
property: 'abc';
}
interface B {
property: string;
}
type r = A extends B ? true : false;
//should be true
console.log(getType<A>().isAssignableTo(getType<B>())); //global type functions not supported
interface A {
a: true;
b: number;
}
console.log(getType<Partial<A>>().getProperties());
console.log(getType<Readonly<A>>().getProperties());
console.log(getType<Pick<A, 'a'>>().getProperties()); //getProperties() shouldn't be empty
class MyClass {
constructor(public a: string) {
}
}
console.log(getType<MyClass>().getProperties()[0]);
Not true, see:
More advanced stuff:
Just a quick look at the code: "advanced" means the basic things need to be supported first, which sadly aren't. |
That's not needed. Bytecode can be generated more efficiently using the AST directly. No need to have a library in-between.
The logic in type guards are inherently required to support resolving generic types. They are part of a TS reflection system, or otherwise the reflection system is not complete. All of that is supported in microsoft/TypeScript#47658 plus much more. So I think the statement about "most advanced runtime reflection system" should be removed. |
Runtime generic import { getType, Type } from "tst-reflect";
function infer<T extends string|number>(): Type
{
return getType<T>();
}
console.log(infer<'abc'>());
console.log(infer<23>()); or import { getType, Type } from "tst-reflect";
function infer<T>(): Type
{
return getType<T>();
}
interface Ifce {}
class Klass {}
console.log(infer<Ifce >());
console.log(infer<Klass>()); Type infer from passed arguments is just not implemented yet. Nobody needed it yet. |
That has nothing to do with runtime generics. Runtime is if the type is inferred from an actual runtime variable, like almost all generics are used. It's one of the basic TS feature to automatically resolve the generic type parameter. With your static generic implementation you have to manually annotate all generic parameters in order to get the runtime type.
I just pointed out that actual runtime generic parameters are supported in the referenced link. I just saw that the following code is generated for function infer(__genericParams__) {
return (__genericParams__ && __genericParams__.T);
} This breaks a lot of code as |
Well I'm not gonna react to everything so late.. Summary to everything: I still think that my concept is advanced. It looks the way Reflection should. Usage is much more advanced and user friendlier than deepkit/types. Sorry. |
Don't get me wrong, I'm not here to bash you or your effort. I appreciate every contribution to runtime types, which includes your efforts. It sometimes comes across harsh when information is shared in an unemotional way. I just pointed out that your claims are objectively wrong. Template literal, index signature, runtime generics are no edge cases. The user facing API of the referenced link is literally almost the same as yours with the Reflection classes, expect that it supports more TypeScript types and has no false claims. It's not about who wins what, I don't care about that. I only care about false claims being pointed out and corrected, where the first has now been done. Your false statements mislead people, which is not ok. Please stop that. It's up to you what you do with that information now and if you correct it. |
Regarding such statements I'd be careful, because microsoft/TypeScript#47658 is more advanced in addition to emitting smaller JS code for runtime type information.
The text was updated successfully, but these errors were encountered: