打字稿:数组内对象的类型推断

时间:2021-01-08 03:58:40

标签: typescript type-inference

为了对提供给我的类构造函数之一的数据结构进行类型验证,我一直在努力完成一些 Typescript 正确的推理。

本质上,我的构造函数接收一个包含对象列表的数组,这些对象包含一个(某种)插件的声明和插件的“自定义配置”,每个。

我需要 Typescript 来确保提供的 customConfigdefaultConfig 上的类型匹配,但是,我没有运气,甚至没有接近它。

我所做的几次尝试变得非常混乱和荒谬,所以我将附上代码的简单表示,希望有助于表达这个想法:

我希望有人可以提供一些光


type Entry = {
    extension: {
        defaultConfig: Record<PropertyKey, unknown>
        install: any
        uninstall: any
    },
    customConfig: Record<PropertyKey, unknown>
}


function initExtensions<I extends Entry[]>(a: I): void { /* ... */ }


initExtensions([
    {
        extension: {
            defaultConfig: { foo: true },
            install: () => {/* ... */ },
            uninstall: () => {/* ... */ },
        },
        customConfig: { foo: true } // <-- SHOULD BE OK
    },
    {
        extension: {
            defaultConfig: { bar: 123 },
            install: () => {/* ... */ },
            uninstall: () => {/* ... */ },
        },
        customConfig: { bar: true }  // <-- Should complain as should be a NUMBER
    },
])

3 个答案:

答案 0 :(得分:3)

我希望,以下解决方案可以几乎达到您的要求。

int r,c;
cin>>r>>c;
int** p=new int*[r];
for(int i=0;i<r;i++) {
    p[i]=new int[c];
}
for(int i=0;i<r;i++) {
delete [] p[i]; 
}
delete [] p;

PLAYGROUND

答案 1 :(得分:1)

你不能真正做你正在寻找的东西,因为 TypeScript 不支持存在类型。 https://github.com/Microsoft/TypeScript/issues/14466

但是,如果您只想验证它是否正确,您可以为每个条目创建一个小包装器。包装器将允许 TypeScript 推断您的

中每个条目的类型
type Entry<T, C extends T> = {
    extension: {
        defaultConfig: T
        install: any
        uninstall: any
    },
    customConfig: C
}

function asEntry<T, C extends T>(entry: Entry<T, C>) { return entry };

function initExtensions(entries: Entry<any, any>[]): void { /* ... */ }

initExtensions([
    asEntry({
        extension: {
            defaultConfig: { foo: true },
            install: () => {/* ... */ },
            uninstall: () => {/* ... */ },
        },
        customConfig: { foo: true } // <-- OK
    }),
    asEntry({
        extension: {
            defaultConfig: { bar: 123 },
            install: () => {/* ... */ },
            uninstall: () => {/* ... */ },
        },
        customConfig: { bar: true }  // <-- ERROR
    })
])

答案 2 :(得分:1)

Todd Skelton 在他的回答中展示的方法也是我所知道的唯一无样板的解决方案。问题是输入数组中的每个条目都是不同的类型(尽管扩展了 Entry),需要在通用函数签名中明确表示,以便正确进行类型检查。由于目前无法指定具有 n 个模板参数的函数,因此您最终会遇到如下情况:

type Entry<C> = {
    extension: { defaultConfig: C };
    customConfig: Partial<C>;
    install: any;
    uninstall: any;
};

type E<C> = Entry<C>;
function initExtensions<C1,C2,C3,C4,C5>(entries: [E<C1>,E<C2>,E<C3>,E<C4>,E<C5>]): void; 
function initExtensions<C1,C2,C3,C4>(entries: [E<C1>,E<C2>,E<C3>,E<C4>]): void; 
function initExtensions<C1,C2,C3>(entries: [E<C1>,E<C2>,E<C3>]): void; 
function initExtensions<C1,C2>(entries: [E<C1>,E<C2>]): void; 
function initExtensions<C1>(entries: [E<C1>]):void; 
function initExtensions(entries:E<any>[]): void {
    // Initialize your extensions here
}

实际上,它以您希望的方式工作,最多 5 个条目,通过将输入表示为不同长度的元组,而不是将输入表示为一种类型的数组,并且填充了独特的类型。这可能看起来很丑陋和奇怪,但实际上这就是库喜欢 lodash type their variadic functions 的方式,所以它有点必要的邪恶。

当然,没有什么能阻止您生成最多 50 个此签名的差异:它仅用于类型检查,不会反映在您的最终输出中。要么,要么一一传递配置对象:

function initExtension<C>(entry: Entry<C>): void {
    // Initialize one extension here
}

initExtension({
    extension: { defaultConfig: { foo: true } },
    customConfig: { foo: true },
    install: () => null,
    uninstall: () => null,
});

这仅仅是 Todds 方法的替代方法。