Skip to content
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

DecoratorsOf<TClass, TFieldName> - Expose decorators to the type system #58836

Closed
6 tasks done
olegbl opened this issue Jun 12, 2024 · 6 comments
Closed
6 tasks done

DecoratorsOf<TClass, TFieldName> - Expose decorators to the type system #58836

olegbl opened this issue Jun 12, 2024 · 6 comments
Labels
Duplicate An existing issue was already created

Comments

@olegbl
Copy link

olegbl commented Jun 12, 2024

πŸ” Search Terms

decorators, decorated, tc39

βœ… Viability Checklist

⭐ Suggestion

Implement a new generic type that exposes the existence of decorators to the type system:

DecoratorsOf<TClass>  // returns decorators applied to class
DecoratorsOf<TClass, TFieldName> // returns decorators applied to field in class

The type would return a union of the types of all decorators applied to the field/class/etc... which allows deriving new types based on the presence or absence of decorators.

Note: This proposal becomes unnecessary if decorators gain the ability to modify the type of the fields/classes/etc... that they decorate.

πŸ“ƒ Motivating Example

You can see a full example in the TypeScript Playground.

As a brief inline example, consider an application with networking capabilities on its data structures. It uses decorators to annotate which fields are networked (and provide the networking implementation for them).

A client that only has remote access to some data structures would only be able to access these remote fields, and not any local ones, but there is currently no way to generate this TypeScript type.

class MyClass {
    @Networked
    networkedValue: number = 0;

    localValue: number = 0;
}

// Note: Using the proposed DecoratorsOf<> type
type DecoratedWith<TClass, TFieldName, TDecorator> =
    TDecorator extends DecoratorsOf<TClass, TFieldName> ? true : false;

type PickFieldsWithDecorator<TClass, TDecorator> = {
    [
        TFieldName in keyof TClass as
        TFieldName extends string
            ? DecoratedWith<TClass, TFieldName, TDecorator> extends true
                ? TFieldName
                : never
            : never
    ]: TClass[TFieldName]
};

type Remote<T> = PickFieldsWithDecorator<T, typeof Networked>;

function testRemoteMyClass(myClass: Remote<MyClass>) {
    myClass.networkedValue = 0;
    // @ts-expect-error: localValue should not be exposed
    myClass.localValue = 0;
}

πŸ’» Use Cases

  1. This functionality would allow deriving types based on decorators.
  2. There are no existing solutions for doing this with only decorators.
  3. Existing workarounds all involve directly or indirectly storing the presence of decorators in other data structures. For example, storing a map of all decorators applied to a class' members as a POJO.
@fatcerberus
Copy link

As you noted, decorators don’t affect the type of a class at all, so how would this even work? The information just isn’t there. Decorators modifying types is, AFAICT, a prerequisite for this feature.

Also:

This isn't a request to add a new utility type

It is.

@olegbl
Copy link
Author

olegbl commented Jun 12, 2024

Good point, I should clarify.

This feature requires decorators to be exposed to the typing system (which is why this is a feature request to TypeScript, instead of just some library), but it does not require the decorators API to allow an end-user to modify the typing system in some way. The latter is what I referred to by:

Note: This proposal becomes unnecessary if decorators gain the ability to modify the type of the fields/classes/etc... that they decorate.


This isn't a request to add a new utility type

It is.

I suppose it could have a different format to make it look more like a language feature than a type (e.g. type Decs = MyClass.decorators['fieldName']) - I don't have any particular requirements on that subject. Since this isn't a type possible to derive, it needs something.

i.e. The purpose of the type isn't utility but basic functionality.

@IllusionMH
Copy link
Contributor

Looks similar to or duplicate of #48413

@olegbl
Copy link
Author

olegbl commented Jun 12, 2024

Yup! Very similar. Only a couple of minor differences:

  1. This is a bit "lower level" and can be used to implement the PickByDecorator<> API from pick types from class by specific decoratorΒ #48413 (shown in the example as PickFieldsWithDecorator<>).
  2. This would also allow fetching decorators on a class, rather than only for class members.

I should also mention #4881 which I think is the equivalent of:

Note: This proposal becomes unnecessary if decorators gain the ability to modify the type of the fields/classes/etc... that they decorate.

@RyanCavanaugh
Copy link
Member

This doesn't seem to generalize very well. Decorators can have arguments and those arguments will absolutely be needed to make the kinds of decisions being discussed here. #4881 or its alternatives seem like the scalable approach.

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Jun 14, 2024
@typescript-bot
Copy link
Collaborator

This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Jun 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

5 participants