Как вывести тип возвращаемого значения из типа параметра в обобщенной функции? - PullRequest
0 голосов
/ 12 сентября 2018

Вот код с условным типом

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?

Обновление

На github уже открыт вопрос , в котором описан мой пример. Таким образом, текущий ответ - «Нет, но возможно в будущем».

Ответы [ 2 ]

0 голосов
/ 07 апреля 2019

Тернарный оператор действительно не очень подходит для универсальных типов:

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();
    }
}
0 голосов
/ 13 сентября 2018

Вы можете использовать функции перегрузки здесь:

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
...