Open samchon opened 4 years ago
Duplicated/related to PRs #33038 and #33290? Duplicate/similar to #4895?
@j-oliveras
Seeing PR #33038, #33290 and issue #4895 using &
operator, their syntax seems like similar with the ^
type operator. However, ^
is not same with the &
operator type. It's right side type is pseudo type for realizing the safe decorator
implementation.
I admit I don't fully understand this proposal, so I might be totally off-base here, but isn't this considered "non-ECMAScript syntax with JavaScript output" and therefore violates the current criteria for feature request?
@fatcerberus
I'd thought that there wouldn't be any problem defining decorator
on the variable definition (let variable: @decorator
), because type definitions are a type of virtual code that would not be compiled out to the JavaScript source code. However, listening you opinion, it can be a violation of the TypeScript's own strategy.
If defining decorator
on the variable definition ((let variable: @decorator
)) is violating the TypeScript's own strategy, I want to suggest another way. It's using the implicit type definition. When using a decorator
function who is using the ^
type operator, the target variable's type would be defined implicitly like below:
@Table()
export class BbsArticle extends Model<BbsArticle>
{
@Column("varchar", {
restrict: ["NORMAL", "NOTICE", "QUESTION", "SUGGESTION"],
default: "NORMAL"
})
public category!: ("NORMAL"|"NOTICE"|"QUESTION"|"SUGGESTION") ^ SomeFunction;
// exact explicit type
@Column("varchar")
public title!; // implicit type -> be (string & SomeFunction)
@Column("varchar", { nullable: true })
public sub_title: string; // origin type is (string ^ SomeFunction), but no problem
@Column("text")
public content!: boolean; // mis-explicit type -> throws compile error
@Column("int", { unsigned: true, default: 1 })
public hits!; // implicit type -> (be number ^ SomeFunction)
}
function Column<Type extends TypeList, Options extends Options<Type>>
(type: string, options?: Options<Type>): SomeFunction;
In similar reason, using ^
(XOR) symbol seems not validate, it's not a matter to changing the ^
symbol to another one. My goal is just to designing a safe decorator who can let TypeScript to move decorator
feature from experimental
to standard.
If you've an idea about the safe decorator, let's argue about it.
It seems like what you want is actually not decorators (which are a runtime feature) but in fact some kind of branded type?
@fatcerberus Nope, I want the exact typed decorator for safe implementation with TypeScript compiler.
I like this idea.
IMHO the decorated entry should dictate type, and decorator could be checked if it adheres to this type.
It is like 'which is older chicken or the egg', but in this case decorators are weaker construct (as they convey additional information); I would expect to enforce type contract from the entry (field, class, property, ...)
@RyanCavanaugh May I edit this issue content to be more detaily?
Outline
Nowadays, lots of famous JavaScript libraries like
typeorm
ornestjs
are supporting thedecorator
feature. However, thedecorator
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
andcontent
arevarchar
andtext
. However, their instance types arenumber
andboolean
. Their instance type must bestring
, but there would not be any compile error when using the TypeScript. It's the dangerous characteristic of thedecorator
what I want to say.I think such dangerous characteristic is the reason why TypeScript is supporting the
decorator
asexperimental
feature for a long time. I want to suggest an alternative solution that can makedecorator
to be much safer, so that TypeScipt can adapt thedecorator
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.Pseudo type operator
^
In JavaScript,
decorator
is a type of function returning a meta function. In the ordinary TypeScript, thedecorator
function would be represented like upper code. Therefore, there's no way to express the variable type who're using thedecorator
.Therefore, I suggest a new pseudo type operator,
^
symbol. With the^
symbol, expressing both variable anddecorator
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 targetdecorator
.^
RightWithin 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.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: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:Also, the safe
decorator
can make intializer construction much safer, too.In the case of
typeorm
, usingstrict
type checking options are discouraged. It's because the olddecorator
can't express the target variable's detailed options likenullable
or auto-assigneddefault
value. Therefore, in the case oftypeorm
, initializer constructor is not supported. Even massive insertion methods are using the dangerousPartial
type, because it can't distinguish which field is whether essential or optional.However, if safe
decorator
implementation with^
type operator is realized, supporting intializer constructor and massive insertion method with exact type are possible. Asdecorator
defining each column contains the exact type information, distinguishing whether which field is essential or optional.API Controllers
In nowadays, many JavaScript libraries like nestjs are wrapping express framework with
decorator
for convenient. However, wrapping features of express components withdecorator
, 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 safedecorator
means: