#How to construct generic classes without knowing the types beforehand

27 messages · Page 1 of 1 (latest)

winter wyvern
#

This is specifically via jsdoc.

I'm trying to dynamically construct objects that share a base type with arguments that share a base type. But I apparently don't have the generics set up properly and I'm not sure what I'm missing to make this work.

This is a small example which omits any of the class functionality and most of the dat props, but shows the problem I'm running into.

tribal beaconBOT
#
claudekennilol#0

Preview:```ts
/**

  • @typedef {object} BaseData
  • @property {'foo' | 'bar'} type
    */

/**

  • @abstract

  • @template {BaseData} T
    */
    class Base {

    /** @type {T} */
    data;

    /**

    • @param {T} data
      */
      constructor(data) {
      this.data = data;
      }
      ...```
heady sentinel
#

make BaseData a union of your other *Data types

/** @typedef {FooData | BarData} BaseData */
jolly ether
#

Yeah, you basically need a fixed set of possible subtypes to narrow this way, @winter wyvern - if you don't, there could be some other BaseData extending class that has type: "foo".

#

If you don't want a fixed list of subtypes like that then you'd need to narrow some other way, either an explicit check like data instanceof Foo or something like a custom type guard.

winter wyvern
jolly ether
#

Pretty much, yeah.

#

Actually having type on your base contract maybe isn't that useful, but I'm assuming this is placeholder for something more useful.

#

Like in a non-class example you might see:

type BaseWhatever = {
    someCommonProp: string;
}

type Foo = BaseWhatever & {
   type: "foo",
   fooProp: string;
}
type Bar = BaseWhatever & {
   type: "bar",
   barProp: string;
}
type Whatever = Foo | Bar;
winter wyvern
#

Yeah that's more straightforward.. I was just trying to do it inline in the js files. I'll probably just define them in a .d.ts file

winter wyvern
# jolly ether Pretty much, yeah.

Here's a pared down version of my real implementation. It's closer, but I'm essentially getting the same thing.

(note that I have ts playground set to javascript. I have actual types declared at the top of the file. Even though the types say they're giving errors, due to how ts playground works, those types behave just as if they were declared properly)

tribal beaconBOT
#
claudekennilol#0

Preview:```ts
const ConfigurationTypes = /** @type {const} */ {
language: "language",
skill: "skill",
}

type BaseChoiceData = {
// type: (typeof ConfigurationTypes)[keyof typeof ConfigurationTypes];
}

type LanguageChoiceData = BaseChoiceData & {
type: typeof ConfigurationTypes[keyof typeof ConfigurationTypes] = "lan
...```

winter wyvern
jolly ether
#

@winter wyvern It looks like the issue there is the illegal syntax here:

type SkillChoiceData = BaseChoiceData & {
    type: (typeof ConfigurationTypes)[keyof typeof ConfigurationTypes] = 'skill';

#

I think that should just be:

type SkillChoiceData = BaseChoiceData & {
  type: "skill"
}
winter wyvern
#

By itself that's a legal type definition

fiery crag
#

you're trying to assign a value in a type?

#

Types are types, they aren't values and don't have values.

jolly ether
#

You're ending up with type: "languge" | "skill", not type: "language" which is why it doesn't narrow when you check it in the runtime code.

#

Personally, I'd generally derive the type from the union:

tribal beaconBOT
#
type BaseChoiceData = {
    // other common properties (not type)
};

type LanguageChoiceData = BaseChoiceData & {
    type: 'language';
   //... other fields
};

type SkillChoiceData = BaseChoiceData & {
    type: 'skill';
    //... other fields
};

type ChoiceData = LanguageChoiceData |  SkillChoiceData;
type ChoiceType = ChoiceData["type"];
//   ^? - type ChoiceType = "language" | "skill"
winter wyvern
#

Though I guess I could define ChoiceType like you've laid out above and then type my actual code against it and that should give me the same result

jolly ether
#

Yeah, "hardcoded strings" aren't really an issue in TS

#

(Even "TS-via-JSDoc-annotations")