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: Array<AThingWithGenericsII<A,B,C>>
}
const anotherThingWithRelated: AThingWithGenericsII<{ 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" } } },
related: []
}
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: [anotherThingWithRelated]
}
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.
CodePudding user response:
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.