是否可以从“ any”类型推断类型?

时间:2019-11-21 04:30:48

标签: typescript type-inference

我想做这样的事情:

interface Foo<T extends any>{
    a: string; 
    b: T; 
}

function createFunctions(items: Foo<any>[]) {
    return items.map(item => () => {
        return item.b; 
    }); 
}

const items = [
    {
        a: "hello",
        b: "foo"
    },
    {
        a: "world",
        b: 909
    }
]; 



const fns = createFunctions(items); 

const a2: string = fns[0]();  
const b2: string = fns[1](); //Should error - TypeScript should know it's a number

也就是说-我有一个类型为Foo的类型,但是该类型可以是任何类型。

我现在有了这些Foos的列表,该列表可以是所有不同类型的,但是我知道它们的类型。

然后,我想创建一个匹配的功能列表,并对这些功能进行类型强制。

我在这里遇到的问题-这些函数将以具有“ any”类型的返回形式返回。如何执行返回类型?

1 个答案:

答案 0 :(得分:1)

如果我对您的理解正确,则b中的每个items属性项都可以具有不同的类型。要保留每种类型,可能的解决方案是使用items元组而不是数组,并为createFunctions声明显式的mapped tuple返回类型:

interface Foo<T> { a: string; b: T; }

// we infer the items parameter via generic type parameter as tuple
// a mapped tuple type is used as return type
function createFunctions<T extends readonly Foo<any>[]>(items: T):
    { [K in keyof T]: () => T[K] extends Foo<any> ? T[K]["b"] : never } {
    return items.map(item => () => {
        return item.b;
    }) as any 
    // TS cannot properly infer return type here (generics + conditional types + mapped tuple)
    // alt cast: as unknown as { [K in keyof T]: () => T[K] extends Foo<any> ? T[K]["b"] : never }
}

items元组类型通过const assertions保留:

const items = [
    { a: "hello", b: "foo" },
    { a: "world", b: 909 }
] as const // <--- preserve the tuple type here

const fns = createFunctions(items); // readonly [() => "foo", () => 909]

const a2: string = fns[0](); // works
const b2: string = fns[1](); // error, 909 expected

Playground

Here is an extended Playground that shows inference of multiple generic parameters