Flow 泛型(Generics)完全指南:编写类型安全的可复用函数、类与类型别名

发布时间:2026/9/21 17:04:14

Flow 泛型(Generics)完全指南:编写类型安全的可复用函数、类与类型别名 Flow 泛型Generics完全指南编写类型安全的可复用函数、类与类型别名【免费下载链接】flowAdds static typing to JavaScript to improve developer productivity and code quality.项目地址: https://gitcode.com/gh_mirrors/flow30/flow泛型又称多态类型是 Flow 静态类型系统的核心能力之一它允许你编写能够作用于任意类型的函数、类与类型别名同时在输入与输出之间保留类型关系。本指南围绕 website/docs/types/generics.md 展开完整讲解 Flow 泛型的语法位置、行为语义、参数化泛型、类型参数默认值与变型variance关键字并结合当前仓库的源码与测试验证底层行为。读完本文你将掌握用泛型写出可复用、类型安全的代码并理解 Flow 与 TypeScript 在泛型上的关键差异。function identityT(value: T): T { return value; }:::info TypeScript 对比 Flow 与 TypeScript 在泛型上有两处关键分歧全默认类型参数不可省略尖括号当所有类型参数都有默认值时仍然必须写Foo不能写Foo详见 Flow 与 TypeScript 对比。类型参数默认不变型invariant把Cnumber拓宽为Cnumber | string会被拒绝需要通过out T/in T显式选择协变或逆变。而 TypeScript 会从使用位置推断变型并保留兼容性例外这会让读写字段的静态保证更弱详见 泛型变型对比。 :::何时使用泛型当函数、类或类型别名需要跨多种类型工作且需要保留输入与输出之间的类型关系时就应使用泛型如果类型本身无关紧要也不需要追踪它使用unknown更合适如果只有固定数量的具体类型用联合类型 表达可能更清晰。警告Flow 不会推断泛型。如果你希望某个东西具有泛型类型必须显式标注它。否则Flow 可能推断出一个比预期更少多态性的具体类型。泛型的语法位置Flow 中泛型可以出现在多种语法位置下面逐一说明。带泛型的函数函数通过在参数列表前添加类型参数列表T来创建泛型。泛型可以出现在函数中任何可以放置类型的地方参数类型或返回类型function methodT(param: T): T { return param; } const f functionT(param: T): T { return param; }带泛型的函数类型函数类型与普通函数一样通过在函数类型参数列表前添加T来创建泛型可用于参数类型或返回类型T(param: T) T它可以直接作为类型使用function method(func: T(param: T) T) { // ... }带泛型的类类通过在类体前放置类型参数列表来创建泛型class ItemT { // ... }泛型可以出现在类中任何可以放置类型的位置属性类型以及方法参数/返回类型class ItemT { prop: T; constructor(param: T) { this.prop param; } method(): T { return this.prop; } }带泛型的类型别名type ItemT { foo: T, bar: T, };带泛型的接口interface ItemT { foo: T, bar: T, }向可调用对象显式提供类型参数你可以在调用处直接为可调用对象的泛型提供类型参数function doSomethingT(param: T): T { // ... return param; } doSomethingnumber(3);也可以在new表达式中为泛型类直接提供类型参数class GenericClassT {} const c new GenericClassnumber();如果只想指定部分类型参数可以使用_让 Flow 为你推断一个类型class GenericClassT, Ustring, Vnumber{} const c new GenericClassboolean, _, string();警告出于性能考虑我们始终建议在能够显式写出具体类型参数时进行标注。_并非不安全但它比显式指定类型参数更慢。泛型的行为泛型像变量一样工作泛型类型与变量或函数参数很像只不过它们用于类型。只要在作用域内你就可以使用它们function constantT(value: T): () T { return function(): T { return value; }; }按需创建任意多个泛型类型参数列表中可以按需放置任意数量的泛型并随意命名function identityOne, Two, Three(one: One, two: Two, three: Three) { // ... }泛型会追踪值当使用泛型类型标注一个值时Flow 会追踪该值确保你不会把它替换成别的东西function identityT(value: T): T { return foo; // Error! }function identityT(value: T): T { value foo; // Error! return value; // Error! }Flow 会追踪通过泛型传入的值的具体类型以便之后继续使用function identityT(value: T): T { return value; } let one: 1 identity(1); let two: 2 identity(2); let three: 3 identity(42); // Error为泛型添加类型约束bounds与unknown类似泛型有一个未知类型面你不能把泛型当作某个具体类型来使用function logFooT(obj: T): T { console.log(obj.foo); // Error! return obj; }你可以先做细化refine但泛型仍然允许任何类型被传入function logFooT(obj: T): T { if (obj obj.foo) { console.log(obj.foo); // Works. } return obj; } logFoo({ foo: foo, bar: bar }); // Works. logFoo({ bar: bar }); // Works. :(正确做法是使用extends关键字给泛型添加约束bound在保留泛型行为的同时只允许特定类型function logFooT extends {foo: string, ...}(obj: T): T { console.log(obj.foo); // Works! return obj; } logFoo({ foo: foo, bar: bar }); // Works! logFoo({ bar: bar }); // Error!约束同样可以用于字面量类型的保持function identityT extends number(value: T): T { return value; } let one: 1 identity(1); let two: 2 identity(2); let three: three identity(three); // Error!⚠ 旧式约束语法提醒extends关键字作为泛型约束自 Flow 0.302 起默认启用。旧代码可能使用遗留的冒号语法例如T: string而非T extends string。迁移细节见 现代 Flow 语法迁移指南。泛型类型起到边界bound的作用在 Flow 中大多数时候当你把一个类型传入另一个更宽泛的类型时会丢失原始类型——Flow 会忘记它曾经更具体过function identity(val: string): string { return val; } let foo: foo foo; // Works! let bar: bar identity(bar); // Error!泛型允许你在添加约束的同时保住更具体的类型。因此泛型上的类型起到边界作用function identityT extends string(val: T): T { return val; } let foo: foo foo; // Works! let bar: bar identity(bar); // Works!注意当你持有一个带约束的泛型值时不能把它当作更具体的类型使用function identityT extends string(val: T): T { let str: string val; // Works! let bar: bar val; // Error! return val; } identity(bar);这一边界语义在仓库的测试中有直接体现tests/generics/generics.js 通过class CX、class DT、泛型方法mS(z:S,u:T):S以及泛型继承class EX extends CX、class GY extends FArrayY等用例验证了泛型在类、方法与继承链中的类型传递与关系保持。参数化泛型parametric polymorphism泛型有时允许你把类型像函数参数一样传进去这被称为参数化泛型或参数多态。例如带泛型的类型别名就是参数化的。使用它时必须提供类型参数type ItemT { prop: T, } let item: Itemstring { prop: value };你可以把它想象成向函数传参只不过返回值是一个可供使用的类型。类作为类型使用时、类型别名和接口都要求你传入类型参数函数和函数类型没有参数化泛型。类class ItemT { prop: T; constructor(param: T) { this.prop param; } } let item1: Itemnumber new Item(42); // Works! let item2: Item new Item(42); // Error!类型别名type ItemT { prop: T, }; let item1: Itemnumber { prop: 42 }; // Works! let item2: Item { prop: 42 }; // Error!接口interface HasPropT { prop: T, } class Item { prop: string; } Item.prototype as HasPropstring; // Works! Item.prototype as HasProp; // Error!为参数化泛型添加默认值与函数参数一样你也可以为参数化泛型提供默认值type ItemT extends number 1 { prop: T, }; let foo: Item { prop: 1 }; let bar: Item2 { prop: 2 };使用该类型时必须带上尖括号就像函数调用必须带括号一样。裸写Item不带即使所有参数都有默认值也会报[missing-type-arg]错误。裸名保留给未应用的类型构造器——应用它时始终需要显式类型参数或者用空回退到默认值。与 TypeScript 的差异TypeScript 允许在全部参数都有默认值时省略整个类型参数列表Foo与Foo等价。Flow 则要求始终写见 全默认泛型参数省略的对比。变型关键字Variance Keywords你可以通过变型关键字指定泛型的子类型行为。默认情况下泛型是不变型invariant的但可以在声明前加out关键字使其协变covariant或加in关键字使其逆变contravariant。完整介绍见 Flow 的变型文档。变型关键字让你更精确地表达使用泛型的意图赋予 Flow 做更精确类型检查的能力。例如你可能希望下面的关系成立type GenericBoxout T T; const x: GenericBoxnumber 3; x as GenericBoxnumber| string;没有out变型关键字时上面的例子无法成立type GenericBoxErrorT T; const x: GenericBoxErrornumber 3; x as GenericBoxErrornumber| string; // Error: number | string is not compatible with number.注意一旦用变型关键字标注泛型Flow 会检查这些类型只出现在与该变型匹配的位置。例如你不能声明一个协变的类型参数却在逆变位置使用它type NotActuallyCovariantout T (T) void; // Error源码与文档层面的佐证变型的底层模型在 website/docs/lang/variance.md 中有完整推导——out对应输出位置返回类型、只读属性、getter 结果in对应输入位置函数参数、只写属性、setter 参数不写关键字则是同时出现在输入输出位置的不变型。违反声明的变型会报[incompatible-variance]错误例如type Boxout T { get(): T; set(val: T): void; }。此外变型也是 Flow 与 TypeScript 的核心分歧之一Flow 的泛型参数默认不变型对比表见 flow-vs-typescript.md而 TypeScript 从使用位置推断变型。⚠ 旧式变型符号提醒out与in变型关键字自 Flow 0.315 起默认启用。旧代码可能使用遗留的/-符号例如T而非out T-T而非in T它们仍会被识别但已弃用。迁移细节见 现代 Flow 语法迁移指南。结合其他类型特性使用泛型泛型不是孤立存在的它与 Flow 的其他类型特性组合使用能发挥最大价值条件类型泛型参数是条件类型conditional types的输入。例如可以基于泛型T编写类型层面的typeof运算符并在传入联合类型时对联合成员做分发distribution——该分发行为仅在检查类型是泛型时启用见 条件类型。映射类型映射类型依赖泛型参数来转换对象类型见 映射类型。类型别名类型别名泛型是参数化的使用时必须为每个泛型传参见 类型别名。联合类型当判别属性来自泛型参数时Flow 无法在联合类型上完成细化因为泛型尚未解析为具体字面量需要将判别属性重构为具体字面量类型见 带泛型的可区分联合。小结特性关键规则错误/注意点泛型定义在函数、函数类型、类、类型别名、接口的参数列表前加TFlow 不推断泛型必须显式标注显式类型参数调用处fnumber(x)、new Cnumber()_可让 Flow 推断部分参数但性能较慢泛型追踪Flow 追踪通过泛型传入值的具体类型赋值其他类型或返回其他类型会报错类型约束T extends Bound约束泛型不能当作更具体类型使用参数化泛型类/别名/接口使用时必须提供类型参数裸名报[missing-type-arg]需写Foo默认值T extends number 1即使全默认也必须写与 TS 不同变型默认不变型out T协变、in T逆变违反位置约束报[incompatible-variance]参见类型别名 — 定义具名类型常与泛型组合使用函数 — 在函数签名中使用泛型变型 — 协变与逆变如何与泛型交互条件类型 — 由泛型类型参数计算出的类型映射类型 — 使用泛型转换对象类型现代 Flow 语法迁移 — 将遗留T: Bound约束与T/-T变型符号迁移到现代关键字形式【免费下载链接】flowAdds static typing to JavaScript to improve developer productivity and code quality.项目地址: https://gitcode.com/gh_mirrors/flow30/flow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/21 17:54:18

3个技巧搞定kris实战项目性能优化

3个技巧搞定kris实战项目性能优化 官方文档翻了三遍还是没看懂?别慌,kris 的文档确实厚,光看配置项就能让人头皮发麻。很多应届生在做 实战项目 时,一上来就照抄示例,结果线上环境一压测,CPU…

2026/9/21 17:54:18

3天搞定曳尾于涂配置,保姆级教程避坑指南

3天搞定曳尾于涂配置,保姆级教程避坑指南 配置环境就卡半天?别慌,这种“曳尾于涂”式的部署困境,老手都见过。很多刚入行的兄弟,对着文档一步步敲命令,结果报错满天飞,心态直接崩了。 这篇 保姆级教程…

2026/9/21 17:54:18

3招吃透四虎影视WWW在线观看免费源码解析

3招吃透四虎影视WWW在线观看免费源码解析 面试被问核心原理答不上来,现场直接黑脸?别慌。很多兄弟在四虎影视WWW在线观看免费这类高并发场景的源码解析上,只背了八股文,没真动手拆过代码。结果一问底层缓存击穿怎么防、视频流如何切片,脑子瞬间空…

2026/9/21 17:49:18

V型调频信号在ISAR成像中的关键技术解析

1. 项目背景与研究意义在现代雷达信号处理领域,调频信号脉冲压缩技术和逆合成孔径雷达(ISAR)成像技术一直是研究热点。国防科技大学这篇硕士论文选题具有鲜明的工程应用背景和理论创新价值。我曾在某研究所参与过类似项目,深知这类…

2026/9/21 3:28:31

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/21 3:33:19

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/21 0:02:23

OpenResearch:构建可复现的开放式研究工作流

第一次看到“OpenResearch”这个名字,我脑子里冒出的不是某个具体软件,而更像一种研究方式的宣言:开放、可复现、可验证。这三件事放在一起,其实比大多数人想象中难得多。过去几年我一直在折腾自己的研究工作流,从纯纸…

2026/9/20 4:54:47

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/20 5:01:23

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/21 10:29:02

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码