ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

TypeScript 接口与类型完全指南:从 interface/type 语法到仓库实战(The Concise TypeScript Book)

TypeScript 接口与类型完全指南:从 interface/type 语法到仓库实战(The Concise TypeScript Book) 文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载导读本文以 The Concise TypeScript Book仓库 website/src/content/docs/book/interface-and-type.md 及韩文版 website/src/content/docs/ko-kr/book/interface-and-type.md为核心系统讲解 TypeScript 中interface与type的定义语法、基本类型、对象类型、联合类型与交叉类型并结合同仓库中differences-between-type-and-interface.md、merging-and-extension.md、type-manipulation.md等章节的源码级内容深入剖析二者的核心差异、扩展与合并机制。读完本文你将能准确判断何时该用interface、何时该用type并掌握利用交叉类型、联合类型与内置工具类型构建复杂类型系统的实战能力。一、通用语法如何定义一个接口或类型在 TypeScript 中接口interface用于定义对象的结构指定对象必须具有的属性或方法的名称与类型。定义接口的通用语法如下interface InterfaceName { property1: Type1; // ... method1(arg1: ArgType1, arg2: ArgType2): ReturnType; // ... }类型type定义的语法与之类似使用type关键字并配合等号type TypeName { property1: Type1; // ... method1(arg1: ArgType1, arg2: ArgType2): ReturnType; // ... };对语法各部分的拆解interface InterfaceName或type TypeName定义接口或类型别名的名称。property1: Type1指定接口的属性及其对应的类型。可以定义多个属性每个属性用分号分隔。method1(arg1: ArgType1, arg2: ArgType2): ReturnType;指定接口的方法。方法由名称、括号内的参数列表以及返回类型构成。可以定义多个方法每个方法用分号分隔。接口示例interface Person { name: string; age: number; greet(): void; }类型示例type TypeName { property1: string; method1(arg1: string, arg2: string): string; };对象字面量的匿名类型形式对象类型也可以不通过interface或type命名直接在变量声明或函数参数处匿名书写。仓库中的 对象类型章节 给出了示例const sum (x: { a: number; b: number }) x.a x.b; console.log(sum({ a: 5, b: 1 }));这种写法适合局部使用的简单结构但一旦结构在多个位置复用就应该提取为具名的interface或type。二、类型type的多种定义形态在 TypeScript 中类型用于定义数据的形状并强制执行类型检查。根据具体使用场景类型的定义有多种常见语法仓库文档将其归纳为以下几类。基本类型Basic Typeslet myNumber: number 123; // 数字类型 let myBoolean: boolean true; // 布尔类型 let myArray: string[] [a, b]; // 字符串数组 let myTuple: [string, number] [a, 123]; // 元组对象与接口Objects and Interfacesconst x: { name: string; age: number } { name: Simon, age: 7 };关于对象类型仓库 对象类型章节 进一步说明TypeScript 中对象类型描述对象的形状不仅指定属性的名称与类型还指定属性是必选还是可选。例如interface User { name: string; age: number; email?: string; // 可选属性 }类型别名同样可以定义对象形状但它的能力不止于此——它可以基于已有类型或已有类型的组合创建新的自定义类型包括联合类型、交叉类型以及其他复杂类型type Point { x: number; y: number; };联合类型与交叉类型Union and Intersection Typestype MyType string | number; // 联合类型 let myUnion: MyType hello; // 可以是字符串 myUnion 123; // 或者是一个数字 type TypeA { name: string }; type TypeB { age: number }; type CombinedType TypeA TypeB; // 交叉类型 let myCombined: CombinedType { name: John, age: 25 }; // 同时拥有 name 和 age 属性其中联合类型union type表示一个值可以是若干类型中的任意一种使用|符号分隔各候选类型交叉类型intersection type表示一个值同时拥有多个类型的所有属性使用符号连接。仓库为这两种类型分别设有独立章节见 联合类型 与 交叉类型// 联合类型值可以是 string 或 number let x: string | number; x hello; // 合法 x 123; // 合法// 交叉类型值同时包含 X 与 Y 的全部属性 type X { a: string }; type Y { b: string }; type J X Y; // 交叉 const j: J { a: a, b: b };三、interface 与 type 的核心差异原文档在介绍两种语法后把二者的区别放在独立章节 타입과 인터페이스의 차이점类型与接口的差异 中专门讨论。这是使用 TypeScript 时最需要厘清的知识点主要有以下三个维度。1. 声明合并Declaration Merginginterface 独有能力接口支持声明合并对同名接口进行多次定义时TypeScript 会把它们合并为包含所有属性与方法的一个接口。而type 不支持声明合并。这一特性在需要为已有类型补充功能、或在不修改原始定义的情况下打补丁扩展第三方库类型时非常有用。interface A { x: string; } interface A { y: string; } const j: A { x: xx, y: yy, };如果对type做同样的重复声明编译器会直接报错——这正是接口可合并、类型别名不可合并的最直观体现。2. 扩展Extensionextends 与 的语法差异类型与接口都支持扩展其他类型/接口但语法不同。接口使用extends关键字继承其他接口的属性和方法但接口无法扩展联合类型等复合类型interface A { x: string; y: number; } interface B extends A { z: string; } const car: B { x: x, y: 123, z: z, };类型使用运算符将多个类型组合为一个类型交叉interface A { x: string; y: number; } type B A { j: string; }; const c: B { x: x, y: 123, j: j, };注意这里type B A {...}交叉的是一个接口与一个内联对象类型展示出类型别名在组合来源上的灵活性。仓库 병합과 확장合并与扩展 章节把这两个概念做了明确区分合并Merging将多个同名声明组合为一个定义。典型场景就是同名接口的多次声明interface X { a: string; } interface X { b: number; } const person: X { a: a, b: 7, };扩展Extension通过扩展或继承已有类型/接口来创建新类型是在不修改原始定义的前提下向既有类型添加属性或方法的机制interface Animal { name: string; eat(): void; } interface Bird extends Animal { sing(): void; } const dog: Bird { name: Bird 1, eat() { console.log(Eating); }, sing() { console.log(Singing); }, };3. 联合类型与交叉类型的表达能力type 更灵活在定义联合类型与交叉类型时type 别名明显更灵活。使用type关键字可以轻松地用|运算符构造联合类型、用运算符构造交叉类型。接口虽然可以间接表示联合类型但并不原生支持交叉类型。type Department dep-x | dep-y; // 联合 type Person { name: string; age: number; }; type Employee { id: number; department: Department; }; type EmployeeInfo Person Employee; // 交叉如果确实需要用接口来表达联合常见的做法是把接口放进联合里——接口本身不能直接写A | B但可以构造接口的联合类型interface A { x: x; } interface B { y: y; } type C A | B; // 接口的联合小结何时选 interface何时选 type综合仓库各章节的论述可以得出如下选型准则需要声明合并如扩展全局类型、第三方库补丁→ 选interface需要继承其他接口、以面向对象方式表达契约 → 选interface配合extends需要联合类型、交叉类型、元组、字符串字面量联合、映射类型等能力 → 选type需要扩展联合类型或无法用extends表达的复合结构 → 选type配合。四、进阶从已有类型创建新类型原文档指出TypeScript 中类型的作用是定义数据形状并强制类型检查。仓库在 타입 조작类型操作 章节中系统展示了从类型创建类型的完整工具箱这些能力正是type别名体系的核心优势可以与接口/类型基础语法组合使用。交叉类型与联合类型 与 |type A { foo: number }; type B { bar: string }; type C A B; // A 与 B 的交叉 const obj: C { foo: 42, bar: hello };type Result string | number; const value1: Result hello; const value2: Result 42;映射类型Mapped Types基于已有类型的属性变换出新类型type MutableT { readonly [P in keyof T]: T[P]; }; type Person { name: string; age: number; }; type ImmutablePerson MutablePerson; // 所有属性变为只读条件类型Conditional Types基于条件推断类型type ExtractParamT T extends (param: infer P) any ? P : never; type MyFunction (name: string) number; type ParamType ExtractParamMyFunction; // string索引访问类型Indexed Access Types通过索引Type[Key]访问另一类型中某个属性的类型type Person { name: string; age: number; }; type AgeType Person[age]; // numbertype MyTuple [string, number, boolean]; type MyType MyTuple[2]; // boolean内置工具类型Utility Types仓库文档列举了最常用的内置工具类型它们是类型编程中最高频的一批工具类型作用示例AwaitedT递归解包 Promise 类型AwaitedPromisestring→stringPartialT将所有属性设为可选PartialPerson→{ name?: string; age?: number }RequiredT将所有属性设为必选Required{name?: string}→{ name: string }ReadonlyT将所有属性设为只读ReadonlyPerson赋值a.name John报错RecordK, T生成键集合 K、值类型为 T 的对象类型Recordstring, ProductPickT, K从 T 中选取指定属性 KPickProduct, price→{ price: number }OmitT, K从 T 中省略指定属性 KOmitProduct, price→{ name: string }ExcludeT, U从联合 T 中剔除 U 中的类型Excludea\|b\|c, a\|c→bExtractT, U从联合 T 中提取 U 中的类型ExtractUnion, a\|c→a \| cNonNullableT剔除 null 与 undefinedNonNullablea\|null\|undefined\|b→a \| bParametersT提取函数参数类型元组Parameters(a: string, b: number) void→[a: string, b: number]ConstructorParametersT提取构造函数参数类型ConstructorParameterstypeof Person→[name: string, age: number]ReturnTypeT提取函数返回类型ReturnType(name: string) number→numberInstanceTypeT提取类实例类型InstanceTypetypeof PersonThisParameterTypeT提取函数this参数的类型ThisParameterTypePerson[greet]→PersonOmitThisParameterT移除函数this参数OmitThisParametertypeof capitalize→() stringThisTypeT标记上下文this类型{ [name: string]: Function } ThisTypeLoggerUppercaseT字符串字面量转大写Uppercaseabc→ABCLowercaseT字符串字面量转小写LowercaseABC→abcCapitalizeT首字母大写Capitalizeabc→AbcUncapitalizeT首字母小写UncapitalizeAbc→abcNoInferT阻止泛型函数中的自动类型推断见下文示例其中几个值得展开的典型用法Partial与Required——常用于配置对象、表单数据等场景type Person { name: string; age: number; }; type A PartialPerson; // { name?: string | undefined; age?: number | undefined; }type Person { name?: string; age?: number; }; type A RequiredPerson; // { name: string; age: number; }Record——构建键值映射结构type Product { name: string; price: number; }; const products: Recordstring, Product { apple: { name: Apple, price: 0.5 }, banana: { name: Banana, price: 0.25 }, }; console.log(products.apple); // { name: Apple, price: 0.5 }ConstructorParameters与InstanceType——配合类使用提取构造参数或实例类型class Person { constructor( public name: string, public age: number ) {} } type PersonConstructorParams ConstructorParameterstypeof Person; // [name: string, age: number] const params: PersonConstructorParams [John, 30]; const person new Person(...params); console.log(person); // Person { name: John, age: 30 }class Person { name: string; constructor(name: string) { this.name name; } sayHello() { console.log(Hello, my name is ${this.name}!); } } type PersonInstance InstanceTypetypeof Person; const person: PersonInstance new Person(John); person.sayHello(); // Hello, my name is John!NoInfer——阻止泛型范围中的自动推断。不使用 NoInfer 时function fnT extends string(x: T[], y: T) { return x.concat(y); } const r fn([a, b], c); // 类型为 (a | b | c)[]使用NoInferT后y不再参与推断编译器会强制y必须与x的元素类型一致function fn2T extends string(x: T[], y: NoInferT) { return x.concat(y); } const r2 fn2([a, b], c); // 报错c 不能赋值给 a | b五、与接口/类型体系协同的相邻知识点为了让接口与类型这个主题形成完整的知识闭环仓库中还有几个与之强相关的章节值得一并掌握。索引签名Index Signatures在 TypeScript 中string、number、symbol都可以作为索引签名使用。这在定义键为字符串/数字、值为统一类型的字典结构时非常常见参见 인덱스 시그니처type K { [name: string | number]: string; }; const k: K { x: x, 1: b }; console.log(k[x]); console.log(k[1]); console.log(k[1]); // 与 k[1] 结果相同注意 JavaScript 会把number索引自动转换为string索引因此k[1]与k[1]返回相同的值。类型注解Type Annotations类型注解是与接口/类型声明配合使用的基础工具见 타입 어노테이션变量可以使用var、let、const声明并选择性添加类型TypeScript 对简单类型有很好的推断能力多数时候无需显式声明const x: number 1;函数参数可以添加类型注解function sum(a: number, b: number) { return a b; }匿名函数lambda同样适用const sum (a: number, b: number) a b;参数有默认值时可以省略该参数的注解const sum (a 10, b: number) a b;函数返回类型可以显式注解——这对复杂函数尤其有帮助因为先写返回类型再写实现有助于在动手前想清楚函数的契约const sum (a 10, b: number): number a b;仓库文档还给出了实用建议通常给类型签名signature添加注解而不给函数体内的局部变量添加对象字面量则始终建议添加类型。never 类型与穷尽性检查接口与类型经常被用来建模有限可能集合此时never类型是配合 switch 穷尽性检查的利器参见 Never 类型。never表示永远不会出现的值用于描述永不返回如无限循环、抛出错误的函数或表达式const infiniteLoop (): never { while (true) { // do something } };const throwError (message: string): never { throw new Error(message); };在联合类型上做穷尽性检查时never能帮助编译器捕捉遗漏的分支type Direction up | down; const move (direction: Direction): void { switch (direction) { case up: // move up break; case down: // move down break; default: const exhaustiveCheck: never direction; throw new Error(Unhandled direction: ${exhaustiveCheck}); } };当未来给Direction增加新的成员如left而switch未覆盖时direction将被推断为该新成员赋值给never会触发编译错误从而在运行时之前发现漏网分支。这与前文接口/类型建模 联合类型 交叉类型的体系形成完整闭环用 type/interface 定义形状用联合类型表达可能性用 never 保证覆盖完整性。六、实践建议与常见陷阱结合原文档与仓库各章节整理出以下实践要点对象契约优先考虑interface需要extends继承、声明合并、面向对象风格时interface是自然选择库作者公开的 API 类型也通常以interface暴露便于使用者通过声明合并扩展。复合类型优先考虑type联合类型|、交叉类型、元组、字面量联合、映射类型、条件类型等类型编程场景只有type能胜任。交叉类型 ≠ 接口继承A B会直接组合所有成员同名属性可能产生never之类的意外结果而interface B extends A允许在类型检查层面更可控地覆盖或补充。二者各有适用场景。善用内置工具类型Partial、Pick、Omit、Record、ReturnType、Parameters等是日常最常用的类型操作能显著减少重复的类型声明。类型注解遵循签名必注、局部可省、字面量必注的仓库建议兼顾可读性与代码简洁。用never做穷尽性检查对联合类型的分支处理坚持写default分支并把分支变量赋给never让编译器替你发现遗漏。参考文档索引本文涉及的核心文档均位于仓库website/src/content/docs/目录下可按需继续深入阅读interface-and-type.md英文原版interface-and-type.md韩文版interface-and-type.md简体中文版differences-between-type-and-interface.md类型与接口的差异merging-and-extension.md合并与扩展type-manipulation.md类型操作object-types.md对象类型union-type.md联合类型intersection-types.md交叉类型index-signatures.md索引签名type-annotations.md类型注解never-type.mdNever 类型赞分享文档教程【免费下载链接】typescript-bookThe Concise TypeScript Book: A Concise Guide to Effective Development in TypeScript. Free and Open Source.项目地址https://gitcode.com/gh_mirrors/typ/typescript-book点击查看免费下载相关推荐TypeScript 接口与类型Interface and Type实战指南The Concise TypeScript Book 深入解析TypeScript 接口与类型Interface and Type实战指南The Concise TypeScript Book 深入解析 本文以《Th文档教程The Concise TypeScript Book 精读接口Interface与类型别名Type的语法、用例与选型The Concise TypeScript Book 精读接口Interface与类型别名Type的语法、用例与选型 本篇指南以开源书籍项目 The文档教程The Concise TypeScript Book 实战指南interface 与 type 的语法体系与联合交叉类型详解The Concise TypeScript Book 实战指南interface 与 type 的语法体系与联合交叉类型详解 本篇技术指南围绕开源项目 Th文档教程上一篇iOS设备虚拟定位技术方案基于iFakeLocation的安全位置模拟实现下一篇解放双手明日方舟MAA自动化助手终极使用指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进