如何创建仅接受具有特定嵌套类型的类型实例的泛型函数?

jay*_*ubi 7 typescript

更新

我自己做了一个解决方案,通过将嵌套类型从静态字段移动到即时字段,这似乎有效但并不完美:https ://tsplay.dev/w26Xjw


更新

主要目的是:

  1. 我想创建一个通用函数<T,U>,它接受两个参数;
  2. 这些参数的类型可以是 connected/related
  3. 当我将第一个参数传递给 T 的类型时,它应该自动推断第二个参数的类型 U

所以问题是:

  1. 如何正确地使这两种类型连接/相关?我尝试使用嵌套类型,如下面我之前的帖子,这可能不是一种合适的方式,但我不知道如何。欢迎任何建议。
  2. 一旦这些类型连接/相关,如果可能的话,是否可以从第一个类型自动推断后一个类型?

这样当用户传递第一个参数时,泛型函数应该限制第二个参数的类型。

我想在 C++ 中写一些类似的东西:

class A {
    class InnerType {}
}

template<typename T>
void test(const T& first, const typename T::InnerType& second);
Run Code Online (Sandbox Code Playgroud)

我想创建一个接受两个参数的通用函数:

  1. 第一个 arg 应该是一种类型,T并且会有一个嵌套类型T.Param
  2. 第二个 arg 应该是一种 T.Param
class A {
    static Param = class {
        ....
    }
}

class B {
    static Param = class {
        ....
    }
}

// How can I make the T/P match the requirements explain above?
function test<T, P>(first:T, second:P) {
}
Run Code Online (Sandbox Code Playgroud)

然后这样的调用应该通过:

test(new A(), new A.Param()); // OK
test(new A(), new B.Param()); // Fail
test(new B(), new A.Param()); // Fail
test(new B(), new B.Param()); // OK
Run Code Online (Sandbox Code Playgroud)

T.J*_*der 6

有几种不同的方法可以做到这一点,部分取决于您想要驱动该过程的参数。您可以使用第一个参数来驱动它:

function test1<T extends {Param: unknown}, P extends T["Param"]>(first: T, second: P) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

或第二个:

function test2<P, T extends {Param: P}>(first: T, second: P) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

有了这些,你会得到这些结果:

test1(A, A.Param); // works
test1(B, A.Param); // error on second argument

test2(A, A.Param); // works
test2(B, A.Param); // error on first argument
Run Code Online (Sandbox Code Playgroud)

两个游乐场


请注意,因为 TypeScript 的类型系统是结构性的(基于类型的形状)而不是名义上的(基于类型的名称),所以在操场链接中我添加了一些东西A.ParamB.Param因此它们不会具有相同的形状。否则,由于它们的形状相同(空类),因此可以使用其中一个代替另一个。

  • 虽然这个答案不符合我的要求,但很有启发。我想保留它。 (2认同)

cap*_*ian 2

这个答案可能对你来说很有趣。

下一个解决方案呢?

class ParamA {
    foo: number = 0
}

class ParamB {
    bar: string = ''
}

class A {
    InnerType = () => ParamA
}

class B {
    InnerType = () => ParamB
}


function test1<
    T extends { InnerType: any },
    P extends InstanceType<ReturnType<T["InnerType"]>>,
    >(first: T, second: P) {
    // ...
}

test1(new A(), new ParamA());
test1(new B(), new ParamA()); // error
test1(new A(), new ParamB()); //error
test1(new B(), new ParamB());
Run Code Online (Sandbox Code Playgroud)