Repository: TypeScript
Issue: Safe decorator implementation with ^ type operator.
Labels: Suggestion,Awaiting More Feedback

## Outline
Nowadays, lots of famous JavaScript libraries like [`typeorm`](https://typeorm.io) or [`nestjs`](https://nestjs.com) are supporting the `decorator` feature. However, the `decorator` feature is not suitable for core philosophy of the TypeScript; the safe implementation. 

When defining a `decorator` onto a *variable*, duplicated definition in the *variable* type must be written. It's very annoying and even dangerous when different type be defined in the *variable* type. The TypeScript compiler can't detect the mis-typed definition.

For an example, look at the below code, then you may find something weird. Right, column types of `title` and `content` are `varchar` and `text`. However, their instance types are `number` and `boolean`. Their instance type must be `string`, but there would not be any compile error when using the TypeScript. It's the dangerous characteristic of the `decorator` what I want to say.

```typescript
@Table()
export class BbsArticle extends Model<BbsArticle>
{
    @Column("varchar", {
        restrict: ["NORMAL", "NOTICE", "QUESTION", "SUGGESTION"],
        default: "NORMAL"
    })
    public category!: "NORMAL"|"NOTICE"|"QUESTION"|"SUGGESTION";

    @Column("varchar")
    public title!: number;

    @Column("varchar", { nullable: true })
    public sub_title!: string | null;

    @Column("text")
    public content!: boolean;

    @Column("int", { unsigned: true, default: 1 })
    public hits!: number;
}

function Column<Type extends TypeList, Options extends Options<Type>>
    (type: string, options?: Options<Type>): SomeFunction;
```

I think such dangerous characteristic is the reason why TypeScript is supporting the `decorator` as `experimental` feature for a long time. I want to suggest an alternative solution that can make `decorator` to be much safer, so that TypeScipt can adapt the `decorator` as a standard feature. 

Key of the alternative solution is to defining the decorator feature not in front of the *variable*, but in the *variable* type definition part. To implement the *variable* type defined decarator, I think a new pseudo type operator `^` is required.

```typescript
@Table()
export class BbsArticle extends Model<BbsArticle>
{
    // ("NORMAL"|"NOTICE"|"QUESTION"|"SUGGESTION") ^ SomeFunction
    public category!: @Column("varchar", {
        restrict: ["NORMAL", "NOTICE", "QUESTION", "SUGGESTION"],
        default: "NORMAL"
    });

    // string ^ SomeFunction
    public title!: @Column("varchar");

    // (string | null) ^ SomeFunction
    public sub_title!: @Column("varchar", { nullable: true });

    // string ^ SomeFunction
    public content!: @Column("text");

    // number ^ SomeFunction
    public hits!: @Column("int", { 
        unsigned: true, 
        default: 1 
    });
}

function Column<Type extends TypeList, Options extends Options<Type>>
    (type: Type, options?: Options): DeductType<Type, Options> ^ SomeFunction;
```




## Pseudo type operator `^`
```typescript
// Decorator is a function returning a function.
function SomeDecorator(): Function;

// Variable type cannot be expressed
var someVariable: @SomeDecorator();
```

In JavaScript, `decorator` is a type of function returning a meta function. In the ordinary TypeScript, the `decorator` function would be represented like upper code. Therefore, there's no way to express the *variable* type who're using the `decorator`.

Therefore, I suggest a new pseudo type operator, `^` symbol. With the `^` symbol, expressing both *variable* and `decorator` types, at the same time, are possible. Left side of the `^` operator would be the *variable* type and that can be assigned or be read as a value. The right side would be a pseudo type representing return type of the target `decorator`.

  - Left `^` Right
    - Left: Variable type to be assigned or to be read.
    - Right: Pseudo type for meta implementation.

Within framework of the type meta programming, both left and right side of the `^` symbol can be all used. Extending types from both left and right side are all possible. However, assigning and reading variable's value, it's only permitted to the left side's type.

```typescript
function SomeDecorator(): number ^ Function
{
    return function ()
    {
        // implementation code
    };
}
type SomeType = ReturnType<SomeDecorator>;

// TYPE EXTENSIONS ARE ALL POSSIBLE
type ExtendsNumber = SomeType extends number ? true : false; // true
type ExtendsColumn = SomeType extends Function ? true : false; // true

// ASSIGNING VALUE IS POSSIBLE
let x: SomeType = 3; // no error

// ASSIGNING THE DECORATOR FUNCTION IS NOT POSSIBLE
let decorator: Function = () => {};
x = decorator; // be compile error
```




## Appendix
### ORM Components
If the safe decorator implementation with the new `^` symbol is realized, there would be revolutionary change in ORM components. TypeScript would be the best programming language who can represents database table exactly through the ORM component and the safe decorator implementation. 

It would be possible to represent the exact columns only with `decorator`s. Duplicated definitions on the member variable types, it's not required any more. Just read the below example ORM code, and feel which revolution would come:

```typescript
@Table()
export class BbsArticle
    extends Model<BbsArticle>
{
    /* -----------------------------------------------------------
        COLUMNS
    ----------------------------------------------------------- */
    // number ^ IncrementalColumn<"int">
    public readonly id!: @IncrementalColumn("int");

    // number ^ ForeignColumn<ForeignColumn>
    public bbs_group_id!: @ForeignColumn(() => BbsGroup);

    // (number | null) ^ ForeignColumn<BbsArticle, Options>
    public parent_article_id!: @ForeignColumn(() => BbsArticle, { 
        index: true, 
        nullable: true 
    });

    // ("NORMAL"|"NOTICE"|"QUESTION"|"SUGGESTION") ^ Column<"int", Options>
    public category!: @Column("varchar", {
        restrict: ["NORMAL", "NOTICE", "QUESTION", "SUGGESTION"],
        default: "NORMAL"
    });

    // string ^ Column<"varchar", Options>
    public writer!: @Column("varchar", {
        index: true, 
        default: () => Random.characters(16) 
    });

    // string ^ Column<"varchar">
    public password!: @Column("varchar");

    // string ^ Column<"varchar">
    public title!: @Column("varchar");

    // (string | null) & Column<"varchar", Options>
    public sub_title!: @Column("varchar", {
        nullable: true 
    }); 

    // string ^ Column<"text">
    public content!: @Column("text");

    // number ^ Column<"int", Options>
    public hits!: @Column("int", {
        unsigned: true,
        default: 0
    });

    // Date ^ CreationTimeColumn
    public created_at!: @CreationTimeColumn();

    // (Date | null) ^ UpdationTimeColumn
    public updated_at!: @UpdationTimeColumn();

    // (Date | null) ^ SoftDeletionColumn
    public deleted_at!: @SoftDeletionColumn();

    /* -----------------------------------------------------------
        RELATIONSHIPS
    ----------------------------------------------------------- */
    public getGroup(): Promise<BbsGroup>
    {
        return this.belongsTo(BbsGroup, "bbs_group_id");
    }

    public getParent(): Promise<BbsArticle | null>
    {
        return this.belongsto(BbsArticle, "parent_article_id");
    }

    public getChildren(): Promise<BbsArticle[]>
    {
        return this.hasMany(BbsArticle, "parent_article_id");
    }

    public getTags(): Promise<BbsTag[]>
    {
        return this.hasManyToMany(BbsTag, BbsArticleTag, "bbs_tag_id", "bbs_article_id");
    }
}
```

If this issue be adopted, so that the safe `decorator` implementation with the `^` symbol is realized in the future TypeScript compiler, even join relationship can be much safer.

Because foreign columns are defined with the safe `decorator`, member variables of the columns have exact information about the reference. Therefore, defining join relationship can be safe with type meta programming like below:

```typescript
export abstract class Model<Entity extends Model<Entity>>
{
    protected async belongsTo<
            Target extends Model<Target>, 
            Field extends SpecialFields<Entity, ForeignColumn<Target>>>
        (target: CreatorType<Target>, field: Field): 
            Promise<Entity[Field] extends ForeignColumn<Target, { nullable: true }>
                ? Target | null
                : Target>;

    protected async hasOne<
            Target extends Model<Target>,
            Field extends SpecialFields<Target, ForeignColumn<Entity>>,
            Symmetric extends boolean>
        (
            target: ObjectType<Target>, 
            field: Field, 
            symmetric: Symmetric
        ): Promise<Symmetric extends true ? Target : Target | null>;

    protected async hasMany<
            Target extends Model<Target>,
            Field extends SpecialFields<Target, ForeignColumn<Entity>>>
        (target: ObjectType<Target>, field: Field): Promise<Target[]>;

    // 1: M: N => 1: X
    protected hasManyToMany<
            Target extends Model<Target>,
            Route extends Model<Route>,
            TargetField extends SpecialFields<Route, ForeignColumn<Target>>,
            MyField extends SpecialFields<Route, ForeignColumn<Entity>>>
        (
            target: ObjectType<Target>,
            route: ObjectType<Route>,
            targetField: TargetField,
            myField: MyField
        ): Promise<Target[]>;

    // M: N => 1: M: 1
    protected hasManyThrough<
            Target extends Model<Target>,
            Route extends Model<Route>,
            TargetField extends SpecialFields<Target, ForeignColumn<Route>>,
            RouteField extends SpecialFields<Route, ForeignColumn<Entity>>>
        (
            target: ObjectType<Target>,
            route: ObjectType<Route>,
            targetField: TargetField,
            routeField: RouteField
        ): Promise<Target[]>;
}
```

Also, the safe `decorator` can make intializer construction much safer, too. 

In the case of [`typeorm`](https://typeorm.io), using `strict` type checking options are discouraged. It's because the old `decorator` can't express the target variable's detailed options like `nullable` or auto-assigned `default` value. Therefore, in the case of [`typeorm`](https://typeorm.io), initializer constructor is not supported. Even massive insertion methods are using the dangerous `Partial` type, because it can't distinguish which field is whether essential or optional.

```typescript
export module "typeorm"
{
    export class BaseEntity<Entity extends BaseEntity<Entity>>
    {
        // NO INITIALIZER CONSTRUCTOR EXISTS
        public constructor();

        // RECORDS ARE DANGEROUS (PARTIAL) TYPE
        // AS CANNOT DISTINGUISH WHETHER ESSENTIAL OR OPTINAL
        public static insert<Entity extends BaseEntity<Entity>>
            (
                this: CreatorType<Entity>, 
                records: Partial<Entity>[] 
            ): Promise<Entity[]>;
    }
}
```

However, if safe `decorator` implementation with `^` type operator is realized, supporting intializer constructor and massive insertion method with exact type are possible. As `decorator` defining each column contains the exact type information, distinguishing whether which field is essential or optional.

```typescript
export class Model<Entity extends Model<Entity>>
{
    public static insert<Entity extends Model<Entity>>
        (this: CreatorType<Entity>, records: Model.Props<Entity>[]): Promise<Entity[]>;

    /**
     * Initializer Constructor
     * 
     * @param props Properties would be assigned to each columns
     */
    public constructor(props: Model.IProps<Entity>);
}

export namespace Model
{
    export type Props<Entity extends Model<Entity>>
        = OmitNever<RequiredProps<Entity, true>>
        & Partial<OmitNever<RequiredProps<Entity, false>>>;
    
    type RequiredProps<Entity extends Model<Entity>, Flag extends boolean> = 
    {
        [P in keyof Entity]: Entity[P] extends ColumnBase<infer Name, infer Options>
            ? IsRequired<Entity[P], Name, Options> extends Flag
                ? ColumnBase.Type<Name, Options>
                : never
            : never
    };

    type IsRequired<
            Column extends ColumnBase<Name, Options>, 
            Name extends keyof ColumnBase.TypeList, Options> =
        Column extends IncrementalColumn<any> ? false
        : Column extends UuidColumn<any> ? false
        : Options extends INullable<true> ? false
        : Options extends IDefault<any> ? false
        : true;
}

type Model.Props<BbsArticle> = 
{
    id?: number;
    bbs_group_id: number;
    parent_article_id?: number | null;
    category?: "NORMAL"|"NOTICE"|"QUESTION"|"SUGGESTION";

    writer: string;
    password: string;

    title: string;
    sub_title?: string | null;
    content: string;
    hits?: number;

    created_at?: Date;
    updated_at?: Date | null;
    deleted_at?: Date | null;
};
```

### API Controllers
In nowadays, many JavaScript libraries like [nestjs](https://nestjs.com) are wrapping [express](https://expressjs.com) framework with `decorator` for convenient. However, wrapping features of [express](https://expressjs.com) components with `decorator`, it loses chance to detecting m is-type-usage error in the compile level.

However, if safe `decorator` implementation with the `^` symbol is used, it also can be used safely. I'll not write the detailed description about the below code. Just look and feel what the safe `decorator` means:

```typescript
@Controller("bbs/:group/articles")
export class BbsArticlesController
{
    @Get()
    public index
        (
            httpReq: @HttpRequest(),
            group: @Param("group", "string"),
            input: @Query<IPage.IRequest>()
        ): Promise<IPage<IArticle.ISummary>[]>;

    @Get(":id")
    public async at
        (
            httpReq: @HttpRequest(),
            group: @Param("group", "string"),
            id: @Param("id", "number")
        ): Promise<IArticle>;

    @Post()
    public async store
        (
            httpReq: @HttpRequest(), 
            group: @Param("group", "string"),
            input: @RequestBody<IArticle>()
        ): Promise<IArticle>;

    @Put(":id")
    public async update
        (
            httpReq: @HttpRequest(),
            group: @Param("group", "string"),
            id: @Param("id", "number"),
            input: @RequestBody<Partial<IArticle>>()
        ): Promise<IArticle>;
}
```