use*_*783 7 javascript generics flowtype
我之前从未用静态类型语言写过.我主要是用Javascript开发的,最近我一直有兴趣了解更多关于FB的Flowtype.
我发现文档编写得很好,我理解其中的大部分内容.但是我不太了解泛型的概念.我试过谷歌搜索一些例子/解释,但没有运气.
有人可以解释什么是泛型,它们主要用于什么,也许提供一个例子?
假设我想编写一个只存储单个值的类.显然这是做作的; 我保持简单.实际上,这可能是一些集合,Array可以存储多个值.
假设我需要包装一个number:
class Wrap {
value: number;
constructor(v: number) {
this.value = v;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我可以创建一个存储数字的实例,我可以得到这个数字:
const w = new Wrap(5);
console.log(w.value);
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好.但是等等,现在我也想换一个string!如果我天真地尝试换一个字符串,我会收到一个错误:
const w = new Wrap("foo");
Run Code Online (Sandbox Code Playgroud)
给出错误:
const w = new Wrap("foo");
^ string. This type is incompatible with the expected param type of
constructor(v: number) {
^ number
Run Code Online (Sandbox Code Playgroud)
这不起作用,因为我告诉Flow Wrap只需要numbers.我可以重新命名Wrap到WrapNumber,然后复制它,调用拷贝WrapString,并更改number到string体内.但这很乏味,现在我有两份相同的东西需要维护.如果我每次想要换一个新类型时都继续复制,这很快就会失控.
但请注意,Wrap实际上并没有对其进行操作value.它不在乎是否是number或string,或别的东西.它只存储它并稍后将其还原.这里唯一重要的不变量是你给它的值和你得到的值是相同的类型.使用什么特定类型并不重要,只是这两个值具有相同的类型.
因此,考虑到这一点,我们可以添加一个类型参数:
class Wrap<T> {
value: T;
constructor(v: T) {
this.value = v;
}
}
Run Code Online (Sandbox Code Playgroud)
T这里只是一个占位符.这意味着"我不在乎你放在这里的类型,但重要的是在任何地方T都使用它,它是相同的类型." 如果我通过你,Wrap<number>你可以访问该value物业,并知道它是一个number.同样地,如果我通过你,Wrap<string>你知道value那个实例是一个string.有了这个新定义Wrap,让我们再试一次包装a number和a string:
function needsNumber(x: number): void {}
function needsString(x: string): void {}
const wNum = new Wrap(5);
const wStr = new Wrap("foo");
needsNumber(wNum.value);
needsString(wStr.value);
Run Code Online (Sandbox Code Playgroud)
Flow推断出类型参数,并且能够理解这里的所有内容都将在运行时工作.如果我们尝试这样做,我们也会出现预期的错误:
needsString(wNum.value);
Run Code Online (Sandbox Code Playgroud)
错误:
20: needsString(wNum.value);
^ number. This type is incompatible with the expected param type of
11: function needsString(x: string): void {}
^ string
Run Code Online (Sandbox Code Playgroud)
(完整示例的tryflow)
静态类型语言中的泛型是一种定义可以应用于任何类型依赖项的函数或类的方法,而不是为每种可能的数据类型编写单独的函数/类。它们确保一个值的类型始终与分配给相同通用值的另一个值的类型相同。
例如,如果您要编写一个将两个参数加在一起的函数,则该操作(取决于语言)可能会完全不同。在JavaScript中,由于它并不是一门静态类型的语言,因此您仍然可以执行此操作并在函数中进行类型检查,但是Facebook Flow允许除单个定义之外的类型一致性和验证。
function add<T>(v1: T, v2: T): T {
if (typeof v1 == 'string')
return `${v1} ${v2}`
else if (typeof v1 == 'object')
return { ...v1, ...v2 }
else
return v1 + v2
}
Run Code Online (Sandbox Code Playgroud)
在此示例中,我们定义一个具有泛型类型的函数,T并说所有参数将具有相同的类型,T并且该函数将始终返回相同的类型T。在函数内部,因为我们知道参数将始终为同一类型,所以我们可以使用标准JavaScript测试其中一个参数的类型,并返回我们认为的参数和该类型的“加法”。
在以后的代码中使用该函数时,该函数可以称为:
add(2, 3) // 5
add('two', 'three') // 'two three'
add({ two: 2 }, { three: 3 }) // { two: 2, three: 3 }
Run Code Online (Sandbox Code Playgroud)
但是,如果尝试以下操作,将引发输入错误:
add(2, 'three')
add({ two: 2 }, 3)
// etc.
Run Code Online (Sandbox Code Playgroud)