推断超级类型的通用包装纸元组

发布于 2025-01-23 08:43:10 字数 2511 浏览 9 评论 0原文

我正在尝试在打字稿中创建一种类型约束,该约束可以为包装类型强制实施Supertype关系。 假设我定义了以下类型(以及用于构建它的实用程序函数):

interface Wrapper<T> { 
    item: T; 
}

function wrap<T>(t: T): Wrapper<T> { 
    return { item: t } 
}

然后,我创建了以下类型来推断超级类型的关系(我在0 vs 下方解释了Never问题):

type SuperTypesWrappers<C, T extends ReadonlyArray<Wrapper<any>>> = {
    [K in keyof T]: T[K] extends Wrapper<infer V> ?
    C extends V ? Wrapper<V> :
    0 : 0 // never : never  -> doesn't work
};

我定义了3个示例包装器,如以下内容:

interface A { a: string; }
const A = wrap<A>({ a: 'a' });

interface B { b: string; }
const B = wrap<B>({ b: 'b' });

interface C extends B { c: string; }
const C = wrap<C>({ b: 'b', c: 'c' });

以及一种验证约束的类型:

// WORKS FINE: type Test1 = [0, Wrapper<B>]
type Test1 = SuperTypesWrappers<C, [typeof A, typeof B]>;

如预期,类型数组中的第一个项目是0,因为a不是c的超级模型,而是b是。

到目前为止,一切都很好。

然后,我创建了一个AUX类型来实施整体数组有效性:它返回数组类型,因为它是从不代码>包装器&lt; x&gt;

type ValidSuperTypesWrappers<X> = X extends ReadonlyArray<Wrapper<any>> ? X : never;

// WORKS FINE: never
type Test2 = ValidSuperTypesWrappers<Test1>;

然后,我创建了一个利用这两种类型的函数:

export function defineHierarchy<C, T extends ReadonlyArray<Wrapper<any>>>(
    wrapper: Wrapper<C>, 
    superWrappers: ValidSuperTypesWrappers<SuperTypesWrappers<C, T>>
): ValidSuperTypesWrappers<SuperTypesWrappers<C, T>> {
    // some implementation
    return superWrappers;
}

当我调用它时,我希望检查第二个参数,在下面的示例中,它应该引起类型错误(基于示例类型test1test2)的情况:

// DOES NOT WORK: should raise type error for the array argument!
// inferred type: const h: readonly Wrapper<any>[]
const h = defineHierarchy(C, [A, B]);

可能我缺少某些东西,还是可能是一个错误?如何更改这些类型以使其在上面的defineHierArchy函数中起作用(可能不指定函数调用中的通用类型参数)?


注1:如果我使用从不:supertypeswrappers中,甚至test2不起作用:

// DOES NOT WORK: type Test2 = [never, Wrapper<B>]
type Test2 = ValidSuperTypesWrappers<Test1>;

注2:我不想依靠partial&lt; t&gt;来表达supertype约束,上面的类型应更好地表示约束。

I'm trying to create a type constraint in TypeScript that enforces supertype relationship for a wrapped type.
Let's suppose I defined the following type (and a utility function to build it):

interface Wrapper<T> { 
    item: T; 
}

function wrap<T>(t: T): Wrapper<T> { 
    return { item: t } 
}

Then I've created the following type to infer the super type relationship (I'm explaining below the 0 vs never issue):

type SuperTypesWrappers<C, T extends ReadonlyArray<Wrapper<any>>> = {
    [K in keyof T]: T[K] extends Wrapper<infer V> ?
    C extends V ? Wrapper<V> :
    0 : 0 // never : never  -> doesn't work
};

I defined 3 example wrappers, like the following:

interface A { a: string; }
const A = wrap<A>({ a: 'a' });

interface B { b: string; }
const B = wrap<B>({ b: 'b' });

interface C extends B { c: string; }
const C = wrap<C>({ b: 'b', c: 'c' });

And a type to verify the constraint:

// WORKS FINE: type Test1 = [0, Wrapper<B>]
type Test1 = SuperTypesWrappers<C, [typeof A, typeof B]>;

As expected, the first item in the type array is 0 because A is not supertype for C, but B is.

So far, so good.

Then I created an aux type to enforce the array validity as a whole: it returns the array type as it is, or never, if it has some items that are not Wrapper<X>:

type ValidSuperTypesWrappers<X> = X extends ReadonlyArray<Wrapper<any>> ? X : never;

// WORKS FINE: never
type Test2 = ValidSuperTypesWrappers<Test1>;

Then I created a function that leverages both types:

export function defineHierarchy<C, T extends ReadonlyArray<Wrapper<any>>>(
    wrapper: Wrapper<C>, 
    superWrappers: ValidSuperTypesWrappers<SuperTypesWrappers<C, T>>
): ValidSuperTypesWrappers<SuperTypesWrappers<C, T>> {
    // some implementation
    return superWrappers;
}

And when I invoke it, I'm expecting the second parameter to be checked, and in the following example it should raise a type error (based on what happens in the example types Test1 and Test2):

// DOES NOT WORK: should raise type error for the array argument!
// inferred type: const h: readonly Wrapper<any>[]
const h = defineHierarchy(C, [A, B]);

Probably I'm missing something, or could it be a bug? How can I change these types to make it work in the defineHierarchy function above (possibly without specifying the generic type arguments in the function call)?


NOTE 1: If I use never : never in SuperTypesWrappers, even Test2 doesn't work:

// DOES NOT WORK: type Test2 = [never, Wrapper<B>]
type Test2 = ValidSuperTypesWrappers<Test1>;

NOTE 2: I would not like to rely on Partial<T> to express a supertype constraint, the type above should represent the constraint better.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文