1
class Base<T> {
    public state = {} as T;
    public getState(): T {
        return this.state
    }
    public setState(v: T) {
        this.state = v
    }
}

interface DogProps {
    name: 'hello';
    age: 123;
}

class Dog extends Base<DogProps> {
    public sayName() {
        console.log('name: ', this.state.name);
    }
    public sayAge() {
        console.log('age: ', this.state.age);
    }
}

function test<U, T extends Base<U>>(Cor: new () => T): [U, T] {
    const dog = new Cor();
    const state = dog.getState();
    return [state, dog];
}

const [state1, dog1] = test(Dog); // state1 is unknow

const [state2, dog2] = test<DogProps, Dog>(Dog); // verbose but right

demo playground

I am newbe in typescript.
I thought the code I wrote was right. But it does not work as expected.
Why state1's type is unknow?
Can I get the right type without test<DogProps, Dog>(Dog)?

much thanks!!!

1 Answer 1

3

This is a side effect of how generic resolution works, typescript sees that T is referred to in the arguments so it tries to resolve it, but the constraint is based on U so it tries to resolve that first. Because U doesn't appear anywhere in the argument list, it can't resolve it so it ends up unknown

If you ensure that U is present in the arguments list you can ensure that typescript will be able to resolve it from just looking at the input without having to figure out T first:

function test<U, T extends Base<U>>(Cor: new()=>(T & Base<U>)): [U, T] {
                                                 // ^here^
}

This should fix the issue :)

Sign up to request clarification or add additional context in comments.

6 Comments

You are my god. You saved my life.
I sure hope your life doesn't depend on something like this 🤣. Happy coding! 😁
Now I understood the first paragraph, the reason why my code does not work. But I still not understand the second paragraph, why your code works. Especially without having to figure out T first. Because return param still need type T. Could you explain more details?
pretend you are typescript, you are looking at the types of arguments and you are trying to figure out what U should resolve to. But U isn't specified anywhere in the input arguments, only T, so how can you figure out what U is? At some point typescript will probably get updated to be able to cope with this case but at least for today using (T & (Constraint of T)) works fine.
As a human being, we know Dog extends Base, then U's type must be DogProps. But typescript seems not smart enough. By the way, could you recommend any books or website or articles to learn advanced typescript skills, like how generic resolution works. It seems that typescript document does not have these things.
|

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.