Отклонение TypeScript с помощью `Type '{} []' нельзя назначить типу 'number'` - PullRequest
0 голосов
/ 17 января 2019

Допустим, я создаю простую функцию для удвоения ввода,

> let f1: (x: number) => number = x => x * 2;
> .type f1
let f1: (x: number) => number

Если я хочу взять первое значение и удвоить его, я могу сделать либо

let f2 = R.pipe( R.take(1), f1 );
let f2 = R.pipe( R.head, f1 );

Обе они работают f2([5,4,3]) вне TypeScript. Тем не менее, с TypeScript я получаю,

> let f2 = R.pipe( R.take(1), f1 );
[eval].ts(6,29): error TS2345: Argument of type '(x: number) => number' is not assignable to parameter of type '(x: {}[]) => number'.
  Types of parameters 'x' and 'x' are incompatible.
    Type '{}[]' is not assignable to type 'number'.

> let f2 = R.pipe( R.head, f1 );
[eval].ts(6,26): error TS2345: Argument of type '(x: number) => number' is not assignable to parameter of type '(x: string) => number'.
  Types of parameters 'x' and 'x' are incompatible.
    Type 'string' is not assignable to type 'number'.

Что я делаю не так. Я даже не знаю, как читать,

Type '{}[]' is not assignable to type 'number'.

и я не понимаю, с чем связано string в

Type 'string' is not assignable to type 'number'.

(я не вижу string нигде).

1 Ответ

0 голосов
/ 18 января 2019

Общая проблема заключается в том, что TypeScript плохо работает с универсальными функциями более высокого порядка: https://github.com/Microsoft/TypeScript/issues/9366.

В большинстве случаев, когда вы передаете универсальную функцию (например, R.take(n) или R.head) в другую (например, R.pipe), вместо сохранения свободных параметров универсального типа, TypeScript автоматически выводит их. Большую часть времени он выводит эти параметры как {}, его пустой тип.

Во втором примере с R.head выводится строка, потому что R.head фактически определяется двумя перегрузками:

// from ramda/index.d.ts
head<T>(list: ReadonlyArray<T>): T | undefined;
head(list: string): string;

и поскольку TypeScript еще не может решить, какую перегрузку использовать (вы не указали ни строку, ни массив), он просто выбирает ее. По моему опыту, он выбирает последний, более подробно об этом здесь: https://github.com/Microsoft/TypeScript/issues/13570

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

let f4 = R.pipe<number[], number, number>( R.head, f1 );

Для вашего примера с R.take(n), согласно Рамде, он на самом деле не должен работать, даже если он напечатал, так как возвращает массив, а не единственное значение:

// from ramda/index.d.ts
take<T>(n: number): {
    (xs: string): string;
    (xs: ReadonlyArray<T>): T[];
};
...