1

This code is posing a problem to me:

var makeVariableOfClass = (sentClass: typeof Entity) => {
    var newEntity = new sentClass();
}

interface EntityProps {
    sentient: boolean;
}

class Entity {
    private sentient: boolean;
    constructor(props: EntityProps) {
        this.sentient = props.sentient
    }
}

class Person extends Entity {
    constructor() {
        super({sentient: true});
    }
}

class Wall extends Entity {
    constructor() {
        super({sentient: false});
    }
}

I'd like to be able to programmatically declare either a person or a wall (in this example), but the typing of Entity in makeVariableOfClass requires the EntityProps, even though I only want to send in a subset of things (Person and Wall). I understand that I could make sentClass be of type typeof Person | typeof Wall, but I'd like to be more scalable than that. Is there another way to get around this without typeof Person | typeof Wall | typeof ... ?

3
  • Are you getting an error? This should work if you give entity a default constructor. Currently it seems like you cannot just call new sentClass() because it wants you to pass in props. Commented Feb 21, 2021 at 3:20
  • new sentClass() would demote Wall and Person to Entity. Commented Feb 21, 2021 at 3:23
  • @RossBush was that in response to B. Witter? I have a similar concern with that Commented Feb 21, 2021 at 4:18

2 Answers 2

3

You could make sentClass be a constructor function with zero parameters that returns something that is compatible with Entity:

let makeVariableOfClass = <TEntity extends Entity>(
  sentClass: new () => TEntity
) => {
  let newEntity = new sentClass();
  return newEntity;
};

const person = makeVariableOfClass(Person); // person: Person
const wall = makeVariableOfClass(Wall); // wall: Wall
const entity = makeVariableOfClass(Entity); // ERR since Entity does not have a zero-arg constructor
const date = makeVariableOfClass(Date); // ERR since new Date does not produce Entity-compatible value
Sign up to request clarification or add additional context in comments.

Comments

0

I resolved it by sending in a constructor function, similar to y2bd's answer but not exactly the same:

let makeVariableOfClass = (createNewClass: () => Entity) => {
  return createNewClass();
}

Obviously this is a bit obtuse in this particular example, but it served my purposes of telling the abstract map class what types of walls to use for different map subclasses.

3 Comments

So you don't care if makeVariableOfClass(Person) returns an Entity instead of specifically a Person?
@jcalz Does the above answer prevent that? Is <TEntity extends Entity> preventing that from happening?
Yes, the other version is a generic function which means that TEntity will be inferred to be the specific instance type of the sentClass parameter passed in. If you call makeVariableOfClass(Person), then sentClass is of type new () => Person which will cause the compiler to infer that TEntity is Person, and thus the return type of the function will also be Person.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.