简体   繁体   中英

How do I make a type-level list of varying Generics in TypeScript?

Given this type:

type AThingWithGenerics<A, B, C> = {
  name: string;
  someFunction: (id: number) => A;
  anotherFunction: () => B;
  loveSomeGenerics: (s: string) => { foo: C };
};

Where A , B , and C are objects that vary across values. For example:

const aThing: AThingWithGenerics<{ foo: string }, { foo: number, bar: string }, { bar: string }> = {
  name: "a_thing",
  someFunction: (id: number) => { return { foo: "bar" }; },
  anotherFunction: () => { return { foo: 3, bar: "foo" } },
  loveSomeGenerics: (s: string) => { return { foo: { bar: "In this case C is an object containing a string" + s } }; },
}

const anotherThing: AThingWithGenerics<{ bar: number }, { aString: string }, { bar: "test" }> = {
  name: "another_thing",
  someFunction: (id: number) => { return { bar: id + 1 }; },
  anotherFunction: () => { return { aString: "test" } },
  loveSomeGenerics: (s: string) => { return { foo: { bar: "test" } } },
}

It's possible to create a tuple of specific AThingWithGenerics :

type ASpecificPileOfThings = [typeof aThing, typeof anotherThing];

It's also possible to make a list of AThingWithGenerics as long as A , B , and C do not vary:

type APileOfTheSameThing<A, B, C> = [AThingWithGenerics<A, B, C>];

But I am trying to add a list of related AThingWithGenerics to AThingWithGenerics , so aThing might include [anotherThing] as its related . The problem is A , B , and C in related will vary.

So how do I create a type that contains varying generics? This is what I have so far:

type AThingWithGenericsII<A, B, C> = {
  name: string;
  someFunction: (id: number) => A;
  anotherFunction: () => B;
  loveSomeGenerics: (s: string) => { foo: C };
  related: [AThingWithGenericsII<A,B,C>]
}

const aThingWithRelated: AThingWithGenericsII<{foo: string, bar: string }, { property: string }, { nestedFoo: number }> = {
  name: "a_thing_with_related",
  someFunction: (id: number) => { return { foo: "This is a string", bar: "" } },
  anotherFunction: () => { return { property: "bar" } },
  loveSomeGenerics: (s: string) => { return { foo: { nestedFoo: 3.1 } } },
  related: [aThing, anotherThing]
}

This does not typecheck, since A , B , and C s types do not unify. How can AThingWithGenericsII be changed so aThingWithRelated type checks?

TypeScript playground link . I'm sure this question about recursive Generics is related, but I couldn't get it to work for my case.

Try using the first interface AThingWithGenerics you have defined but with this added in, you do not need the others :

type AThingWithGenerics<A = any, B = any, C = any> = {
  name: string;
  someFunction: (id: number) => A;
  anotherFunction: () => B;
  loveSomeGenerics: (s: string) => { foo: C };

  // some things might not have relatives
  related?: Array<AThingWithGenerics>
};

Using type any with the generic definitions will make typescript infer the types of generics used in a specific instance. We do this to allow the related property to use any generics that will ultimately be inferred by typescript.

Just to add the sentiment behind the interface, I figured not all "things" will be related so that is why it is possibly undefined , which was the initial ts error found on the link you provided.

Playgound

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM