TypeScript: возможно ли вывести тип в зависимости от того, успешно ли выполнен вызов функции? - PullRequest
0 голосов
/ 17 апреля 2020

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

function foo(val: string | number): void {
  if (typeof(val) !== 'number') {
    throw new Error('val must be a number');
  }
  // do something with number
}

Можно ли написать сигнатуру foo так, чтобы после ее вызова компилятор сделал вывод, что val должно быть числом?

const val: string | number = getVal();

foo(val);

// Compiler shouldn't complain here since a string would have cause foo to throw
const x = Math.sqrt(val); 

Ответы [ 2 ]

1 голос
/ 17 апреля 2020

Функция перегрузки сделает это. Например,

function foo(val: string): void;
function foo(val: number): number;
function foo(val: string|number) {
  if (typeof(val) !== 'number') {
    throw new Error('val must be a number');
  }
  return Math.sqrt(val);
}

Math.sqrt(foo(123)); // ok
Math.sqrt(foo('asdf')); // not ok

Смотрите на Typescript Playground .

0 голосов
/ 17 апреля 2020

Если у вас есть void -возвратная функция, которая имеет эффект сужения типа одного из его параметров, и если вы используете TypeScript 3.7 или выше, вы можете сделать ее функцией подтверждения и компилятор примет это утверждение во внимание. Возвращаемый тип функции подтверждения начинается с модификатора asserts и сопровождается условием, которое мы хотели бы, чтобы функция утверждала. Это условие может быть либо именем одного из входов функции, либо предикатом типа , который сообщает один из входов функции is более узкого типа, чем объявленный тип. Вот как мы это сделаем с foo():

function foo(val: string | number): asserts val is number {
    if (typeof (val) !== 'number') {
        throw new Error('val must be a number');
    }
    // do something with number
}

Итак, мы изменили void на asserts val is number. Если функция вернется, тип val будет сужен от string | number до number по желанию:

const val: string | number = Math.random() < 0.5 ? "str" : 123;

foo(val);

const x = Math.sqrt(val); // okay

Обратите внимание, что функции утверждений работают только на void - возвращая функции, поэтому у вас не может быть функции, которая действует как утверждение типа , а возвращает некоторое значение. Есть и другие предупреждения (например, они требуют, чтобы явные аннотации назывались ). Но ваш вопрос настолько идеально подходит для функций утверждения, что, если бы я не знал лучше, я бы подумал, что об этом попросил один из разработчиков языка, чтобы продемонстрировать всю мощь функций утверждения! 10

Хорошо, надеюсь, это поможет; удачи!

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

...