Тип на основе generi c (тип параметра функции) - PullRequest
0 голосов
/ 24 марта 2020

Я хочу иметь тип переменной, основанный на типе параметра функции. Я пытался использовать дженерики, но у меня все еще есть какая-то ошибка.

interface A {
    value: string;
}

interface B {
    value: number;
}

interface extA extends A {
    id?: string;
}

interface extB extends B {
    id?: number;
}

function foo<T extends A | B>(param: T) {
    const newParam: T extends A ? extA : extB = param;

    newParam.id = param.value;

    return newParam;
}


const a = { value: "1" } as A;
const b = { value: 1 } as B;

const resultA = foo(a); // resultA is "extA" not "extA | extB"
const resultB = foo(b); // resultB is "extB" not "extA | extB"

Код составлен, но он показывает идею. В зависимости от типа параметра функции param я хочу использовать расширенный тип любого из основных типов newParam. Поэтому, если я выберу параметр одного из каждого типа, TS будет знать, какой тип возвращается. Как этого добиться?

TS Playground

1 Ответ

1 голос
/ 25 марта 2020

Если вам не нужны генерики, вы можете использовать перегрузку функций в TS:

function foo(param: A): extA;
function foo(param: B): extB;
function foo(param: A | B): extA | extB {
    const newParam: extA | extB = param;
    newParam.id = param.value;

    return newParam;
}

Полная игровая площадка

Тип определен правильно.

Но вы должны следить за реализацией функции - вы возвращаете extA | extB то, что может быть недопустимым с предыдущими перегрузками (разработчик может ошибиться в реализации или добавить новую перегрузку и забыть о реализации).
Пример :

function foo(param: A): extA;
function foo(param: B): extB;
function foo(param: A | B): extA | extB {
    const newParam: extB = {
        value: 3,
        id: 22
    };

    return newParam; // always returned only `extB`
}

const a = { value: "1" } as A;
const b = { value: 1 } as B;

const resultA = foo(a);
const resultB = foo(b);

resultA.value // type detected as string
// (correct according to overloading) but implementation
// returns always number what is correct according to its definition
// but incorrect according to previous overload signatures - developer mistake

Детская площадка

...