Issue
If I pass a Class I'd like to return its type. Right now I cast the type after returning the parent's type.
I'd Like to avoid the casting and preserving all intellisense features, is there a way?
Below is an example of implementations and what I'd like to achieve
class Component {
    get name(): string {
        return this.constructor.name
    }
}
class Direction extends Component {
    x: number
    y: number
    constructor(x: number = 0, y: number = 0) {
        super()
        this.x = x
        this.y = y
    }
}
class Rectangle extends Component {
    x: number
    y: number
    w: number
    h: number
    constructor(x: number, y: number, w: number, h: number) {
        super()
        this.x = x
        this.y = y
        this.w = w
        this.h = h
    }
}
class Entity {
    components: Map<string, Component>
    constructor(...components: Component[]) {
        this.components = new Map()
        components.forEach(component => this.add(component))
    }
    get(component: Function): Component | undefined {
        return this.components.get(component.name)
    }
    add(component: Component) {
        this.components.set(component.name, component)
    }
}
const player = new Entity(
                    new Rectangle(100, 100, 100, 100),
                    new Direction(1, 1)
                )
const shape = player.get(Rectangle) as Rectangle
const direction = player.get(Direction) as Direction
Example of what I'd like to have
get(component: Function): ?? return the child type somehow ?? | undefined {
    return this.components.get(component.name)
}
const shape = player.get(Rectangle) // No casting
                            Solution
Looks like you just need a generic so that the type of the given constructor is retained in the return type:
get<C extends new (...args: any[]) => any>(component: C): InstanceType<C> | undefined {
    return this.components.get(component.name) as InstanceType<C>;
}
Since we're passing a class and not an instance, the type of component should be a constructor. Then in the return type, to get the type of an instance, we use the built-in InstanceType.
@kikon's shorter (and better) version:
get<T>(component: new (...args: any[]) => T): T | undefined {
    return this.components.get(component.name) as T;
}
This removes the need for InstanceType as it lets the compiler infer the instance type for us (as T) and the generic constraint.
Answered By - caTS
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.