首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

TypeScript 类型体操-语法入门篇

  • 24-12-16 12:05
  • 2497
  • 9264
juejin.cn

TypeScript 类型体操-语法入门篇

  • TypeScript 类型体操-语法入门篇
  • TypeScript 类型体操-常见套路篇
  • TypeScript 类型体操-常见套路总结

TypeScript 给 JavaScript 添加了一套静态类型系统,通过 TS Compiler 可以将 TS 编译为 JS,在编译的过程做类型检查。

这样就使得 JavaScript 从动态类型语言变成了静态类型语言,可以在编译期间做类型检查,提前发现一些类型安全问题。

为什么有类型体操

  • 简单的类型系统

比如一个 add 函数既可以做整数加法、又可以做浮点数加法,却需要声明两个函数:

c++
代码解读
复制代码
int add(int a, int b) {     return a + b; } double add(double a, double b) {     return a + b; }

这样做会感觉有些死板,如果类型能作为参数传递是不是会更好。

  • 支持泛型的类型系统

泛型表示一种通用的类型,它可以代表任何一种类型,也叫做类型参数。

c++
代码解读
复制代码
T add(T a, T b) {     return a + b; }

这样的泛型虽然会灵活一点,但是对于 JavaScript 来说可能还有点不太够。

比如我们有一个自定义的对象类型。

强类型中,比如Java,对象都是由一个类new出来的,有了类型,就可以获取到类的信息。

但是 JavaScript 不一样,JavaScript中有对象字面量,可以凭空创建一个对象。

如果有一个函数是一个返回对象某个属性值的函数,类型该怎么写呢?

c++
代码解读
复制代码
function getPropValue(obj: T, key): key对应的属性值类型 { return obj[key]; }

好像拿到了 T,也不能拿到它的属性和属性值,如果能对类型参数 T 做一些逻辑处理就好了。

  • 支持类型编程的类型系统

在 Java 里面,拿到了对象的类型就能找到它的类,进一步拿到各种信息,所以类型系统支持泛型就足够了。

但是在 JavaScript 里面,对象可以字面量的方式创建,还可以灵活的增删属性,拿到对象并不能确定什么,所以要支持对传入的类型参数做进一步的处理。

对传入的类型参数(泛型)做各种逻辑运算,产生新的类型,这就是类型编程。

比如上面那个 getProps 的函数,类型可以这样写:

ts
代码解读
复制代码
function getPropValueextends object, Key extends keyof T>(obj: T, key: Key): T[Key] { return obj[key]; }

这里的 keyof T、T[Key] 就是对类型参数 T 的类型运算。

TypeScript 的类型系统就是第三种,支持对类型参数做各种逻辑处理,可以写很复杂的类型逻辑。

TypeScript 类型系统支持哪些类型和类型运算?

TypeScript 支持的类型

JavaScript 中支持的类型,TypeScript 也都支持。

  • 简单类型: number、boolean、string、object、bigint、symbol、undefined、null
  • 包装类型: Number、Boolean、String、Object、Symbol。
  • 复杂类型:Class、Array 等。
TypeScript 特有的类型
Tuple 元祖

元组(Tuple)就是元素个数和类型固定的数组类型:

ts
代码解读
复制代码
type Tuple = [number, string];
Interface 接口

接口(Interface)可以描述函数、对象、构造器等复合类型

ts
代码解读
复制代码
interface IPerson { name: string; age: number; } class Person implements IPerson { name: string; age: number; } const obj: IPerson = { name: 'guang', age: 18, };
Enum 枚举

枚举(Enum)是一系列值的复合:

ts
代码解读
复制代码
enum Transpiler { Babel = 'babel', Postcss = 'postcss', Terser = 'terser', Prettier = 'prettier', TypeScriptCompiler = 'tsc', } const transpiler = Transpiler.TypeScriptCompiler;
字面量类型

TypeScript 还支持字面量类型,也就是类似 123、'aaaa'、{ a: 1} 这种值也可以做为类型。

其中,字符串的字面量类型有两种,

  • 普通的字符串字面量,比如 'aaa'
  • 模版字面量,比如  `aaa${string}` ,它的意思是以 aaa 开头,后面是任意 string 的字符串字面量类型。

所以想要约束以某个字符串开头的字符串字面量类型时可以这样写:

image.png

特殊类型
  • never: 代表不可达,比如函数抛异常的时候,返回值就是 never。
  • void: 代表空,可以是 undefined 或 never。
  • any: 是任意类型,任何类型都可以赋值给它,它也可以赋值给任何类型(除了 never)。
  • unknown: 是未知类型,任何类型都可以赋值给它,但是它不可以赋值给别的类型。
类型装饰

TypeScript 的类型系统还支持描述类型的属性,比如是否可选,是否只读等:

ts
代码解读
复制代码
interface IPerson { readonly name: string; age?: number; } type tuple = [string, number?];

TypeScript 支持的类型运算

获取类型:typeof

typeof 操作符可以用来获取一个变量声明或对象的类型。

ts
代码解读
复制代码
interface Person { name: string; age: number; } const sem: Person = { name: 'semlinker', age: 33 }; type Sem = typeof sem; // -> Person function toArray(x: number): Array<number> { return [x]; } type Func = typeof toArray; // -> (x: number) => number[]
获取类型的键:keyof

keyof 可以用于获取某种类型的所有键,其返回类型是联合类型。

ts
代码解读
复制代码
interface Person { name: string; age: number; } type K1 = keyof Person; // "name" | "age" type K2 = keyof Person[]; // "length" | "toString" | "pop" | "push" | "concat" | "join" type K3 = keyof { [x: string]: Person }; // string | number
遍历:in

in 用来遍历联合类型:

ts
代码解读
复制代码
type Keys = 'a' | 'b' | 'c'; type Obj = { [p in Keys]: any; }; // -> { a: any, b: any, c: any }
泛型约束:extends

有时候我们定义的泛型不想过于灵活或者说想继承某些类等,可以通过 extends 关键字添加泛型约束。

ts
代码解读
复制代码
interface Lengthwise { length: number; } function loggingIdentityextends Lengthwise>(arg: T): T { console.log(arg.length); return arg; }

这时我们需要传入符合约束类型的值,必须包含必须的属性:

ts
代码解读
复制代码
loggingIdentity(3); // Error, number doesn't have a .length property loggingIdentity({ length: 10, value: 3 }); // 正确用法
条件运算:extends ? :

TypeScript 里的条件判断是  extends ? :,可以理解成 if else。

ts
代码解读
复制代码
type isString = T extends string ? true : false; type res1 = isString<'123'>; type res2 = isString<123>;

image-1.png

推导:infer

如何提取类型的一部分呢?答案是 infer。

比如提取元组类型的第一个元素:

ts
代码解读
复制代码
type First<Tuple extends unknown[]> = Tuple extends [infer T, ...infer R] ? T : never; type res = First<[1, 2, 3]>;

image-2.png

联合:|

联合类型(Union) 代表类型可以是几个类型之一

ts
代码解读
复制代码
type Union = 1 | 2 | 3;
交叉:&

交叉类型(Intersection)

  • 相同的类型做合并
ts
代码解读
复制代码
type ObjType = { a: number } & { c: boolean }; let obj: ObjType = { a: 2, c: false, };
  • 不同的类型做舍弃
ts
代码解读
复制代码
type ObjType = (number | string | symbol) & string; // 此时 ObjType 只能是 string
case
  • 修改对象类型的值类型
ts
代码解读
复制代码
interface Person { name: string; age: number; } type MyPerson = { [P in keyof Person]: { value: Person[P] }; };

image-4.png

  • 修改对象类型的 key 类型
ts
代码解读
复制代码
interface Person { name: string; age: number; } type MyPerson = { [P in keyof Person as `get${P & string}`]: Person[P]; };

image-5.png

注:本文转载自juejin.cn的既见君子的文章"https://juejin.cn/post/7448462026944757771"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

104
前端
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top