-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Generics inference of type (static) intersection on instance shape #7934
Comments
BTW, I know that I'm sending the This is probably why T&Z = {} I just don't know how to "extract" the instance shape from a |
@RyanCavanaugh I'd love to hear your insights on this. |
It sounds like you potentially want to pass in the prototypes of each constructor, or you want to write function mergeTypes<T, Z>(type1: new() => T, type2: new() => Z): new () => T & Z {
// Do some work to mixin the types...
} Also see some of the discussion that went on over at #4559. |
@DanielRosenwasser This is a complex issue, so I will try to simplify a bit, I will only address the core issue I see: // Simple class that holds a Type.
// Has 2 type param's that are bound and represent both "types" of a class.
class TypeWrapper<T, TType extends new () => T> {
constructor(private _type: TType) {}
getType(): TType {
return this._type;
}
}
// A factory of TypeWrapper
// this trick enables return the typeof type dynamically
function make<T, TType extends new () => T>(type: TType) {
return new TypeWrapper<T, typeof type>(type);
}
let typeWrapper = make(class A {});
const Clazz = typeWrapper.getType();
let cls = new Clazz(); Now, what did the compiler inferred as type for If we look at the instance But what does the compiler think about The compiler knows that It's seems strange that the compiler knows
|
btw in the playground atleast, hovering over
|
One solution would be #7234. That would make the "simplified" example work as expected. This is sort of an abuse of generics since you don't really want two type parameters there, but would work. The alternative is #6606 (assuming it supported |
filed #7966 to track the crash in quick info |
@RyanCavanaugh #7234 and #6606 are spot on! Here's the interesting thing about your suggestion with #6606:As I said, I'm working on a lib for mixin's and type composition with realtime type composition. export interface ConcreteTypeOf<T> extends Function { new (...args): T; }
class TypeWrapper<T, TType extends ConcreteTypeOf<T>> {
constructor(private _type: new () => T, dupe: TType = undefined) {}
get asType(): T { return <any>this._type; }
get asStaticType(): TType { return <any>this._type; }
mixType<Z, ZType extends new () => Z> (t: ConcreteTypeOf<Z>, dupe: ZType = undefined)
: TypeWrapper<T & Z, ConcreteTypeOf<T & Z> & TType & ZType> {
return <any>this;
}
} Here are some notable changes from the "simplified" example:
Note the return type Here's an example of what we get from it: export class A{
static IM_STATIC_A: string;
imInstanceA: string;
}
class B_{
static IM_STATIC_B: string;
imInstanceB: string;
}
class C_{
static IM_STATIC_C: string;
imInstanceC: string;
} let tw = new TypeWrapper(A, A)
.mixType(B_, B_)
.mixType(C_, C_);
// let's expose out our new type to the world:
export const Composed = tw.asStaticType;
export type Composed = typeof tw.asType; Quite Cool! However I had to remove the intersection of mixType<Z, ZType extends new () => Z> (t: ConcreteTypeOf<Z>, dupe: ZType = undefined)
: TypeWrapper<T & Z, ConcreteTypeOf<T & Z>> {
return <any>this;
} Here's why... class D {
static IM_STATIC_D: string;
imInstanceD: string;
}
let twD = new TypeWrapper(Composed,Composed)
.mixType(D, D);
export const DComposed = twD.asStaticType;
export type DComposed = typeof twD.asType; If we don't remove the
If we remove it, we loose static type meta but have full instance shape. Also worth noting, both with I really like the outcome, even without static meta tough its an issue. If these issues are solved it will make the type system super super flexible. Thanks! |
@RyanCavanaugh Now matter what you do, if the compiler cant infer an instance type from it's static type you can't fill the missing gap. |
Closing in favor of #7234 |
I'v build a nice library for composition of types (mixin) in a dynamic way so the bookkeeping overhead of having to write stand-in members is not needed. (the lib also has some other features and customisation for composition).
It works great but I have one last bookkeeping overhead that bothers me, The lib requires to explicitly set the Type parameters since I can't get it to work when I let typescript infer the types.
Here's an example of what i'm facing:
TypeScript Version:
1.8.9
Code
A
andB
are "example" classes, we will use them for demonstration.Each have one
static
member and oneinstance
member, we will use them verify the output when mixin them together.A "naive" approach using a simple function:
A more explicit approach with a control unit and state.
An implicit attempt first, let the compiler infer for us
Finally, a working version, but we need to explicitly express what we want:
If i'll be able to remove the need to explicitly express the type I will be able to have an easy API for composition/mixin what ever, that can create type's on the fly and save a reference for them (compile time type reference) as if they were defined expressively.
The text was updated successfully, but these errors were encountered: