Сужение общего типа возвращаемого значения

#typescript

Вопрос:

У меня есть функция, которая немного похожа на эту:

 function getOutput<TInputType>(input: TInputType): TInputType {
    if (typeof input === 'string') {
        return 'abc';
    } else {
        return input;
    }
}
 

Игровая площадка TS

В этом коде есть ошибка TS в третьей строке: Type 'string' is not assignable to type 'TInputType'.

Но так как мы проверяем , что typeof input это string так, то, возвращаясь 'abc' , мы возвращаем тот же тип, input что и . Но, похоже, TS не в состоянии сделать такой вывод в данном случае.

Есть ли способ сделать ТС счастливой здесь? (кроме кастинга, @ts-игнорировать и друзей)

Ответ №1:

Машинопись верна, чтобы сообщить об ошибке. Рассмотрим вызов функции getOutput<'xyz'>('xyz') . Согласно определению функции, тип возвращаемого значения должен быть 'xyz' таким, поскольку именно таким является параметр типа TInputType для этого вызова. Однако написанный код фактически возвращается 'abc' , который не может быть присвоен типу 'xyz' .

Таким образом , нет никакого способа «сделать машинопись счастливой» с помощью этого кода, за исключением использования преднамеренно некорректного поведения, такого как утверждение типа или @ts-ignore , потому что сам код является некорректным.

Ответ №2:

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

 function getOutput(input: string): string;
function getOutput<P>(input: P): P;
function getOutput<P, T extends string | P>(input: T): T | string {
    if (typeof input === 'string') {
        return 'abc';
    } else {
        return input;
    }
}

const iAmString = getOutput('a'); // string
const iAmAnything = getOutput(2   3); // number
const iAmAnythingElse = getOutput(new Date()); // Date
 

Игровая площадка TS

Комментарии:

1. Это ошибка с TS 4.4.2 в playground: typescriptlang.org/play?ts=4.4.2#code/…

2. Можете ли вы более конкретно рассказать о самом типе? Это помогло бы. Если тип TInputType = string | number , например, работает.

3. Это может быть что угодно, никаких ограничений.

4. type TInputType = any; все еще работает. Для этого требуется определение типа.

5. Я бы хотел, чтобы TInputType был параметром общего типа , а не просто any any изменял, хотя я пойду туда, если нет других вариантов.