推断函数的返回类型,知道一个属性的值

时间:2019-05-05 07:57:48

标签: typescript typescript-generics

有办法吗?我知道,可以/不可以或切换“类型”属性以获取特定的接口。但是我可以用函数(或方法)的返回值做类似的事情吗?

interface test1 {
    type: 'test1'
}

interface test2 {
    type: 'test2'
}

type unType = test1 | test2;

//i know property "type"'s value
//can i somehow use this information to infer specific type (test1 or test2)
function whichType<T>(typeValue): T {

    return null;
}

const tt1 = whichType<unType>('test1');// should be interface test1
const tt2 = whichType<unType>('test2');// should be interface test2

2 个答案:

答案 0 :(得分:3)

您可以按照TJ Crowder的建议使用重载,如果您只有几个接口,这可能是最好的解决方案,因为编写理解很容易。

更通用的解决方案是使用Extract条件类型根据传入的字符串提取类型:

interface test1 { type: 'test1' }

interface test2 { type: 'test2' }

type unType = test1 | test2;

function whichType<K extends unType['type']>(typeValue: K): Extract<unType, {type: K}> {
    return null!;
}

const tt1 = whichType('test1'); // test1
const tt2 = whichType('test2'); // test2

可以构建一个适用于任何联合的解决方案,但由于typescript不支持部分类型参数推断,因此它要求您使用函数currying:

function whichType<T extends { type: string}>() {
    return function <K extends T['type']>(typeValue: K): Extract<T, {type: K}> {
        return null!;
    }
}

const tt1 = whichType<unType>()('test1'); // test1
const tt2 = whichType<unType>()('test2'); // test2

答案 1 :(得分:2)

如果通过使用函数重载调用whichType时确实使用文字,则可以从类型角度进行操作:

interface test1 {
    type: 'test1'
}

interface test2 {
    type: 'test2'
}

type unType = test1 | test2;

function whichType(typeValue: 'test1'): test1;
function whichType(typeValue: 'test2'): test2;
function whichType(typeValue: string): unType {
    switch (typeValue) {
        case 'test1':
            return <test1>null;
        case 'test2':
            return <test2>null;
        default:
            throw new Error(`Unknown type ${typeValue}`);
    }
}

const tt1 = whichType('test1'); // tt1's type is test1
const tt2 = whichType('test2'); // tt2's type is test2

On the playground

从代码注释中可以看到,您仍然需要运行时逻辑来在运行时进行处理。

要允许在对whichType的调用中使用非文字字符串,您需要添加另一个重载:

function whichType(typeValue: string): unType;

...然后处理您不知道类型的事实。 :-|

[在操场上] [2]

[2]:函数whichType(typeValue:string):unType;