Home > Enterprise >  Type parameter 'T' has a circular constraint
Type parameter 'T' has a circular constraint

Time:01-06

I'm trying to create a generic type which will consist of the argument type, and an array of itself under nodes. My code:

type Foo<T> = T & {
    nodes: Foo<T>[]
}

function Bar<A extends Foo<A>>():null{
    return null;
}

When trying to run it, I'm getting

Type parameter 'A' has a circular constraint

Which I understand. The problem is, this is exactly what I want. I want to use it like so:

interface Vegetables{
    id:number
    nodes: Vegetables[]
}

interface Fruits{
    id:number
    nodes: Fruits
}

Bar<Vegetables>()
Bar<Fruits>

And I'm not sure what I'm missing

code example

CodePudding user response:

Ok, I found a workaround.

Since we're extending, we're keeping the T. So this should still work

type Foo<T> = {
    nodes: Foo<T>[]
}

function Bar<A extends Foo<A>>():null{
    return null;
}

// desired usage:

interface Vegetables{
    id:number
    nodes: Vegetables[]
}

interface Fruits{
    id:number
    nodes: Fruits[]
}

Bar<Vegetables>()
Bar<Fruits>

But if anyone has a way to make it work in the original way, please leave a response

CodePudding user response:

It is not clear what this type parameter is supposed to do, but I have the feeling you want this to fail

interface Stuff {
    id:number
    nodes: Vegetables[]
    type: 'stuff' // adding a discriminant so that Stuff ≠ Vegetables
}

// @ts-expect-error: Stuff is not Stuff & { nodes: Stuff[] }
Bar<Stuff>()

It is not pretty, but you can do it this way

function Bar<
    A extends Foo<unknown> & Check,
    Check = A extends Foo<A> ? unknown: never
>():null{
    return null;
}

Since unknown is the neutral element of intersection, Check does not affect the first type parameter when the constraint is met, and since this condition does not return A, it is not a circular constraint.

Now, you don't need to return never when the constraint is not met, any type which is incompatible with Foo<unknown> will be an error, so you can return some error message explaining that A should be recursive.

  • Related