Giter Site home page Giter Site logo

Comments (7)

marcj avatar marcj commented on June 1, 2024 7

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.

from tst-reflect.

Hookyns avatar Hookyns commented on June 1, 2024

Hi @marcj, welcome to my humble repository.
I've read your proposal few days ago, it is interesting. 🙂

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.
Sorry if I missed something, it's quite large proposal with a lot of materials...


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.

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.

  • You don't have to use any decorators and you can get type of classes/interfaces/whatever from ANY 3rd party package and that package does not have to count with that. This is one of the main features which throws majority of the other reflection systems behind.
  • You can get type of generic parameter (Which reflection system allows this? I didn't check them all, I don't even know them all, maybe there are some...),
  • you can get type of anything (classes, types, interfaces, primitives, unions, intersections, ...),
  • it is plain TypeScript, no schemas, no annotations nor decorators,
  • Type is quite rich (check the synopsis), there are properties, their types, modifiers, decorators with constant arguments; methods with generic types, constraints, parameters, constructors with all the overloads,.. almost everything you need and there is still more.
  • Of course circular references are no problem,
  • metadata can be generated into one file (configurable), that means you have library and you can look up the types and use dynamic imports to load the classes and work with them.
Eg. BE frameworks can find all the constructors by simple linq:
const controllers = Type.getAll().filter(type => type.isSubclassOf(getType<ControllerBase>()));

or find all methods decorated by @route("/path"):

const action = "/todo";

const decoratedMethods = Type.getTypes()
    .flatMap(type => type.getMethods().map(method => ({ method, type })))
    .filter(entry => entry.method.getDecorators().some(decorator => decorator.name == "route" && decorator.getParameters()[0].startsWith(action)));

for (let entry of decoratedMethods)
{
    const Ctor = entry.type.getCtor();
    const controllerInstance = new Ctor();
    controllerInstance[entry.method.name]();
}

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.

from tst-reflect.

marcj avatar marcj commented on June 1, 2024

How would it run in the browser?

It runs in any JS environment, just like yours.

Size of generated metadata is something which can be easily changed

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.

Well, according to your text, this reflection system is level 3, which is ,,Advanced reflection". Your words.

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 extends support (your isAssignableTo is only very rudimentary compared to what x extends y is really capable of, check for example a more complete implementation).

You can get type of generic parameter

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>>();
//built-in classes are not supported
console.log(getType<Map<string, string>>());
console.log(getType<Set<string>>());
console.log(getType<Uint8Array>());
console.log(getType<Date>());
console.log(getType<ArrayBuffer>());
//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]);

you can get type of anything

Not true, see:

  • Runtime type infer does not support Set, Map, typed arrays, etc.
  • Template literals not supported
  • No index signatures

More advanced stuff:

  • No type decorator support (for example for adding validator/ORM information and read them easily without fiddling around with intersections)
  • No parent relationship in nested types (property signature to object literal for example, or parameter to method)

Just a quick look at the code: "advanced" means the basic things need to be supported first, which sadly aren't.

from tst-reflect.

marcj avatar marcj commented on June 1, 2024

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.

That's not needed. Bytecode can be generated more efficiently using the AST directly. No need to have a library in-between.

Create just the plain Reflection system standard. Type guards, validators, schemas,.. it is not Reflection.

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.

from tst-reflect.

Hookyns avatar Hookyns commented on June 1, 2024

Runtime generic
This works.

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.
And still, this base usage is something nobody has. This is advanced feature.

from tst-reflect.

marcj avatar marcj commented on June 1, 2024

Runtime generic
This works.

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.

And still, this base usage is something nobody has

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 infer:

function infer(__genericParams__) {
        return (__genericParams__ && __genericParams__.T);
    }

This breaks a lot of code as arguments is changed. Any code with dynamic parameters that use arguments will break this way. (for example if ES5 is the target). Also infer.length yields an unexpected/wrong value.

from tst-reflect.

Hookyns avatar Hookyns commented on June 1, 2024

Well I'm not gonna react to everything so late..

Summary to everything:
You've just picked all the edge cases to throw it away. You are comparing "jung" package in alpha stage with something what is developed by 13 people several years. Congratulation, you are winner!

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.

from tst-reflect.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.