TSern
January 24, 2024, 4:01am
#1
Is it possible to serializable for Generic type?
@ccclass('Dictionary')
export class Dictionary<K>
{
@property([String])
keys: string[] = []
@property([K]) //Can not do this, cause K is a type, not a value
value: K[] = []
}
After this, I have a component storage the Dictionarty
value
@ccclass
export class DComp extends cc.Component
{
@property(Dictionary/**<cc.Component>**/)
dic: Dictionary<cc.Component> = new Dictionarty<cc.Component>();
}
So, the DComp only showing the keys
property. Cause im not put the right type
inside the @property
of the value
. I tested with [undefinded]
and [cc.Object]
, but it still not right.
Is there another way. And I don’t want to force the K
to extends any other class.
zhangxm
January 24, 2024, 8:53am
#2
@dumganhar is it possible to serialize generic type values?
rybones
January 25, 2024, 12:56am
#3
TypeScript doesn’t allow using a generic type parameter as a decorator argument.
This is because TypeScript’s type system is erased during compilation, and decorators are a runtime feature.
Maybe one option would be achieving it by Mixins?
microsoft:master
← microsoft:mixinClasses
opened 12:23AM - 30 Jan 17 UTC
This PR expands upon #13604 to add support for mixin classes and constructors. T… he PR includes type system support for the ECMAScript 2015 mixin class pattern described [here](http://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/) and [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) as well as rules for combining mixin construct signatures with regular construct signatures in intersection types.
In the following, the term *mixin constructor type* refers to a type that has a single construct signature with a single rest argument of type `any[]` and an object-like return type. For example, given an object-like type `X`, `new (...args: any[]) => X` is a mixin constructor type with an instance type `X`.
A *mixin class* is a class declaration or expression that `extends` an expression of a type parameter type. The following rules apply to mixin class declarations:
* The type parameter type of the `extends` expression must be constrained to a mixin constructor type.
* The constructor of a mixin class (if any) must have a single rest parameter of type `any[]` and must use the spread operator to pass those parameters as arguments in a `super(...args)` call.
Given an expression `Base` of a parametric type `T` with a constraint `X`, a mixin class `class C extends Base {...}` is processed as if `Base` had type `X` and the resulting type is the intersection `typeof C & T`. In other words, a mixin class is represented as an intersection between the mixin class constructor type and the parametric base class constructor type.
When obtaining the construct signatures of an intersection type that contains mixin constructor types, the mixin construct signatures are discarded and their instance types are mixed into the return types of the other construct signatures in the intersection type. For example, the intersection type `{ new(...args: any[]) => A } & { new(s: string) => B }` has a single construct signature `new(s: string) => A & B`.
Putting all of the above rules together in an example:
```ts
class Point {
constructor(public x: number, public y: number) {}
}
class Person {
constructor(public name: string) {}
}
type Constructor<T> = new(...args: any[]) => T;
function Tagged<T extends Constructor<{}>>(Base: T) {
return class extends Base {
_tag: string;
constructor(...args: any[]) {
super(...args);
this._tag = "";
}
}
}
const TaggedPoint = Tagged(Point);
let point = new TaggedPoint(10, 20);
point._tag = "hello";
class Customer extends Tagged(Person) {
accountBalance: number;
}
let customer = new Customer("Joe");
customer._tag = "test";
customer.accountBalance = 0;
```
Effectively, a mixin class declaration is required to pass its constructor arguments through to the abstract base class constructor, and the result is an intersection of the declared class constructor and the base class constructor. For example, adding explicit type annotations to the code above:
```ts
interface Tagged {
_tag: string;
}
function Tagged<T extends Constructor<{}>>(Base: T): Constructor<Tagged> & T {
return class extends Base {
_tag: string;
constructor(...args: any[]) {
super(...args);
this._tag = "";
}
}
}
const TaggedPoint: Constructor<Tagged> & typeof Point = Tagged(Point);
let point: Tagged & Point = new TaggedPoint(10, 20);
point._tag = "hello";
```
The type of `TaggedPoint` is an intersection of two constructor types, `Constructor<Tagged>` and `typeof Point`. Since `Constructor<Tagged>` is a mixin constructor type, its construct signature is "mixed into" the constructor for `Point`. Thus, `TaggedPoint` has a single construct signature with the same parameter list as `Point` but with the return type `Tagged & Point`.
Mixin classes can constrain the types of classes they can mix into by specifying a construct signature return type in the constraint for the type parameter. For example, the following `WithLocation` function implements a subclass factory that adds a `getLocation` method to any class that satisfies the `Point` interface (i.e. that has `x` and `y` properties of type `number`).
```ts
interface Point {
x: number;
y: number;
}
const WithLocation = <T extends Constructor<Point>>(Base: T) =>
class extends Base {
getLocation(): [number, number] {
return [this.x, this.y];
}
}
```
Fixes #4890.
Fixes #10261.