Javascript 函数表达式的流泛型类型(箭头函数)

Javascript 函数表达式的流泛型类型(箭头函数),javascript,generics,flowtype,arrow-functions,parameterized-types,Javascript,Generics,Flowtype,Arrow Functions,Parameterized Types,我通常试图将流函数类型与其实现分开。当我写的时候,它的可读性稍微好一些: 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

我通常试图将流函数类型与其实现分开。当我写的时候,它的可读性稍微好一些:

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);       // √
参见

类型H=(输入:T)=>T;
常数h2:H=i=>i;
常数h3:H=i=>i;
常量hString:string=h3('apple');
常数hNumber:number=h2(7);

所以我注意到,如果我使用,它会起作用:

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' });  // √
H型=(输入:T)=>T;
常数h:h=i=>i;
常数a:string=h('apple');//√
常数b:number=h(7);//√
常数c:{}=h({nane:'jon'});//√

不要问我为什么。

我认为您的代码和类型定义的根本问题是基于对泛型的特定属性(也称参数多态性)的误解:参数性

Parametericity表示泛型函数必须不知道其多态参数/返回值的类型。它是类型不可知论的

因此,泛型函数必须平等地对待与多态类型关联的每个值,而不考虑具体类型。当然,这是相当有限的。当一个函数对它的参数一无所知时,除了返回不变的参数外,它不能对它做任何事情

让我们来看一个不正确的泛型函数:

const f = <a>(x :a) :a => x + "bar"; // type error
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!?!
const f=

所以你的问题仍然是合理的,不幸的是,我不能给你一个食谱。希望在未来的版本中,Flow的行为会发生变化


在您自己的回答中,您建议使用有界泛型。我不会这样做,因为它解决了一个根本不存在的问题,因为这似乎是对这种多态性的滥用。

如果我使用
(I:t)=>I
流转储类型
我得到
(input:t)=>混合的
,老实说,这有点奇怪。这应该是
(I:t)=>T
转储到
[类型:(i:T)=>T]
;你的意思是
(i:T)=>i
的类型应该是
(i:T)=>T
?如果是这样,我同意。除非你的意思是我把定义搞错了,否则这不是一个真正的类型定义,这是类型的实际函数定义。是的,这就是我在问题中的问题。虽然这段代码可能会回答这个问题,但提供关于为什么和/或这段代码如何回答这个问题的额外上下文可以提高它的长期价值。是的,在flow提出解决方案之前,我的答案看起来像是一个黑客,但它实际上按照预期工作,并且类型检查错误用法。但谢谢你的详细回答。看起来像是流程中的一个bug,还是不是?会对为什么感兴趣!
const f = <a>(x :a) :a => x + "bar"; // type error
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
const f = <a>(x :a) :a => x + "bar"; // type error

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