Простая функция с условным типом - PullRequest
0 голосов
/ 03 сентября 2018

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

function test<T extends boolean>(a: T): T extends true ? string : number {
  return a ? '1' : 1
}

Машинопись сообщает, что:

Type '1 | "1"' is not assignable to type 'T extends true ? string : number'.
  Type '1' is not assignable to type 'T extends true ? string : number'.

Я предполагаю, что упускаю что-то очевидное Как я могу построить эту функцию, чтобы машинопись правильно выводила тип на основе аргумента функции?

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

Ответы [ 2 ]

0 голосов
/ 03 сентября 2018

TypeScript правильно определяет тип возвращаемого значения. Чего он не делает, так это того, что он не проверяет, соответствует ли логика времени выполнения условию, указанному в условном типе, и в вашем случае вызывает ошибку во время компиляции. Вы можете обойти ошибку, используя доступ с индексированным типом, чтобы получить требуемый тип на основе условия.

Он будет иметь другое поведение по сравнению с test, который объявлен в вашем вопросе, а именно будет выводить тип объединения в случае, когда тип не известен во время компиляции. Реализация по-прежнему не будет проверяться на соответствие логике условного типа, но ошибки нет, и нет необходимости в утверждениях типа:

interface Selector {
    t: string;
    f: number;
}

function test<T extends boolean>(a: T): Selector[T extends true ? 't' : 'f'] {
  // NOTE: not checked that is returns correct type actually
  return a ? '1' : 1
}


const t1 = test(true);  // string
const t2 = test(false); // number
declare var b: boolean;
const t3 = test(b); // string | number, which may or may not be what you want
0 голосов
/ 03 сентября 2018

Короткий ответ: ты не можешь. Никакое значение не будет присвоено неразрешенному условному типу (условному типу, который все еще зависит от свободной переменной универсального типа). Единственное, что вы можете сделать, это использовать утверждение типа.

function test<T extends boolean>(a: T): T extends true ? string : number {
  return (a ? '1' : 1)  as any
}

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

function test<T extends boolean>(a: T): T extends true ? string : number
function test(a: boolean): number | string {
    return (a ? '1' : 1)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...