如何从泛型函数中的参数类型推断出返回类型?

时间:2018-09-12 20:06:50

标签: typescript conditional-types typescript2.8

这是一些带有条件类型的代码

class A {
    public a: number;
}

class B {
    public b: number;
}

type DataType = "a" | "b";

type TData<T extends DataType> =
    T extends "a" ? A :
    T extends "b" ? B :
    never;

现在,我想使用条件类型作为从函数参数到其返回类型的链接。我试图以不同的方式实现这一目标,但没有结果:

function GetData<T extends DataType>(dataType: T): TData<T> {
    if (dataType == "a")
        return new A();
    else if (dataType == "b")
        return new B();
}

正确的语法是什么?可以使用TypeScript 2.8吗?

更新

已经有一个opened issue on github涵盖了我的示例。 因此,目前的答案是“不,但将来可能会出现。”

2 个答案:

答案 0 :(得分:3)

您可以在此处使用函数重载:

function GetData(dataType: "a"): A;
function GetData(dataType: "b"): B;
function GetData(dataType: DataType): A | B {
    if (dataType === "a")
        return new A();
    else if (dataType === "b")
        return new B();
}

const f = GetData('a');  // Inferred A
const g = GetData('b');  // Inferred B

答案 1 :(得分:0)

三元运算符在泛型类型中确实不能很好地发挥作用:

type TriviallyA<T extends DataType> = 
      T extends any ? A : A;
function GetData<T extends 'a' = 'a'>(dataType: T): TriviallyA<T> {
    return new A(); // Error: Type 'A' is not assignable to type 'TriviallyA<T>'
}

但是泛型确实可以很好地与属性查找配合使用,因此您可以定义一个接口以将字符串映射到特定类型,然后可以使用keyof和属性查找来充当TData

interface DataTypeMapping {
    a: A;
    b: B;
}
type DataType = keyof DataTypeMapping;
type TData<T extends DataType> = DataTypeMapping[T];

function GetData<T extends DataType>(dataType: T): TData<T> {
    // now expected return type is A | B so this is valid!
    if (dataType === 'a') {
        return new A(); 
    } else if (dataType === 'b') {
        return new B();
    }
}