Да, мой ответ кажется хаком до тех пор, пока поток не найдет решение, но на самом деле оно работает, как ожидалось, и тип проверяет неправильное использование Но спасибо за ваш подробный ответ.

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

type Fn = string => string;
const aFn: Fn = name => `hello, ${ name }`;

скорее, чем:

const aFn = (name: string): string => `hello, ${ name }`;

При использовании универсальных типов мы можем написать:

const j= <T>(i: T): T => i;

const jString: string = j('apple'); // √
const jNumber: number = j(7);       // √

Но как я могу отделить этот тип от выражения функции?

type H<T> = (input: T) => T;
const h:H<*> = i => i;              // --> WHAT SHOULD GO FOR '*'?

const hString: string = h('apple'); // X error
const hNumber: number = h(7);       // X error

Что следует использовать для*? any будет работать, но это не то, что я хочу.

В haskell это не проблема:

identity :: a -> a
identity a = a

identity "a-string" // √
identity 666        // √

Видетьflow.org/try

 MinusFour06 окт. 2017 г., 03:04
Если я сделаю<T>(i : T) => i с участиемflow dump-types я получил<T>(input : T) => mixedчто немного странно, если честно.
 norbertpy06 окт. 2017 г., 03:49
Которые должны быть<T>(i: T) => T который сбрасывается в<T>[type: (i: T) => T];
 MinusFour06 окт. 2017 г., 04:15
Вы имеете в виду, что тип<T>(i : T) => i должно быть<T>(i: T) => T? Если так, я согласен. Если вы не имели в виду, что я неправильно понял определение, это не определение типа, это фактическое определение функции с типами.
 norbertpy06 окт. 2017 г., 04:21
Да, это то, что у меня есть в вопросе.

Ответы на вопрос(3)

 type H<T> = (input: T) => T;
    const h2:H<*> = i => i;   
    const h3:H<*> = i => i;   
    const hString: string = h3('apple');
    const hNumber: number = h2(7);
 LW00115 окт. 2017 г., 10:44
Хотя этот код может ответить на вопрос, предоставление дополнительного контекста относительно того, почему и / или как этот код отвечает на вопрос, повышает его долгосрочную ценность.
Решение Вопроса

Итак, я заметил, что если я используюограниченные дженерикисработает

type H<T> = <T: *>(input: T) => T;
const h:H<*> = i => i;

const a: string = h('apple');      // √
const b: number = h(7);            // √
const c: {} = h({ nane: 'jon' });  // √

Не спрашивайте меня, ПОЧЕМУ.

 Andru18 янв. 2019 г., 13:04
Похоже, ошибка в потоке, или это не так? Был бы заинтересован в ПОЧЕМУ!

что основная проблема с вашим кодом и определениями типов основана на неправильном понимании определенного свойства обобщенных типов (он же параметрический полиморфизм):Parametricity.

Параметричность утверждает, что универсальная функция не должна ничего знать о типах своих полиморфных аргументов / возвращаемого значения. Это тип агностика.

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

Давайте посмотрим на неправильную обобщенную функцию:

const f = <a>(x :a) :a => x + "bar"; // type error

Пытаться

f не печатать чек, как ожидалось, потому чтоf не должен относитьсяx какString, Поток обеспечивает параметричность.

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

type F<X, Y> = (x: X) => Y;

const apply = <X, Y>(f: F<X, Y>, x: X) :Y => f(x);

const sqr = (x :number) :number => x * x;
const toUC = (s :string) :string => s.toUpperCase();

apply(sqr, 5); // does type check
apply(toUC, "foo"); // does type check

Пытаться

Почему вы определяете конкретную версиюapply для каждого возможного типа? Просто примените его к значениям произвольного типа при условии, что типыf а такжеx совместимы.

Заключение

Когда у вас есть неограниченная универсальная функция, вы можете применить ее к любому значению, которое вы хотите - оно всегда работает как положено.Так что на самом деле нет причин объявлять отдельную функцию для каждого возможного типа. Умные люди изобрели полиморфизм, чтобы избежать именно этого.

Однако проблема остается. Как только вы отделите определение универсального типа от объявления функции, Flow больше не будет обеспечивать параметричность:

const f = <a>(x :a) :a => x + "bar"; // type error

type G<a> = a => a;
const g :G<*> = x => x + ""; // type checks!?!

Пытаться

Так что ваш вопрос все еще обоснован и, к сожалению, я не могу предложить вам рецепт. Надеемся, что поведение Flow изменится в будущих версиях.

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

 norbertpy21 окт. 2017 г., 16:55
Да, мой ответ кажется хаком до тех пор, пока поток не найдет решение, но на самом деле оно работает, как ожидалось, и тип проверяет неправильное использование Но спасибо за ваш подробный ответ.

Ваш ответ на вопрос