本篇笔记为整理和学习记录笔记,一方面整理之前在
字节跳动青训营
学习时的笔记,一方面也开始接着往后面学习
ts介绍
What? -- 什么是typeScript
TypeScript
是一种由微软开发的开源编程语言,它是JavaScript
的超集。它在JavaScript
的基础上添加了静态类型系统和一些其他新特性,旨在提高大型应用程序的可维护性和开发效率。
TypeScript的主要特点包括:
- 静态类型检查:通过类型注解,TypeScript能够在编译阶段检测出类型错误,这有助于开发者早期发现和修复问题。
- 类型推断:即使没有明确的类型注解,TypeScript也能根据变量的初始值或赋值推断出其类型。
- 对ECMAScript最新特性的支持:TypeScript紧跟ECMAScript的发展,支持包括箭头函数、类、模块等在内的现代JavaScript特性。
- 模块系统:TypeScript有自己的模块系统,可以方便地管理代码的组织和依赖关系。
- 类和接口:TypeScript引入了类和接口的概念,使得面向对象的编程更加清晰和强大。
- 增强的工具支持:许多现代的开发工具和IDE(如Visual Studio Code)对TypeScript提供了优秀的语法高亮、自动补全和错误检查等功能。
最终,TypeScript代码会被编译成普通的JavaScript代码,可以在任何支持JavaScript的环境中运行。通过使用TypeScript,开发者可以在编写JavaScript应用时享受到静态类型的优点,同时保持与现有JavaScript生态系统的兼容性。
Why? -- 为什么要使用typeScript
- 静态类型检查: TypeScript引入了静态类型系统,这可以在编译阶段检测出类型错误,而不是在运行时。这有助于提前发现并修复潜在的bug,提高代码质量。
- 可维护性和可读性: 类型注解使得代码更易于理解和维护,特别是在大型和复杂的项目中。类型信息可以帮助开发者更快地理解代码的作用和预期行为。
- 智能提示和自动补全: 集成开发环境(IDE)可以利用TypeScript的类型信息提供更准确的代码提示和自动补全功能,提高开发效率。
- 面向对象编程支持: TypeScript支持类、接口、泛型等面向对象编程特性,使得构建复杂、模块化的应用程序变得更加容易。
- 最新的JavaScript特性的支持: TypeScript紧跟ECMAScript的发展,支持最新的语言特性和语法,同时还可以向下兼容旧版本的JavaScript。
- 渐进式采用: TypeScript是JavaScript的超集,这意味着你可以逐步将现有的JavaScript项目转换为TypeScript,而无需立即重构整个项目。
- 更好的工具集成: 许多现代前端和后端开发工具与TypeScript有良好的集成,提供了丰富的代码分析、优化和调试功能。
- 大型项目的优势: 对于大型、长期维护的项目,TypeScript的类型安全性和可维护性优势尤其明显,可以降低维护成本和风险。
- 更好的团队协作: 类型系统有助于在团队开发环境中保持代码一致性,减少由于误解或假设导致的错误。
How -- 怎样用?
基础数据类型
基础数据类型的话其实和js基本没区别,左右两边都可以在ts中运行,因为ts有自动类型推断,如下图👇
然后ts中的基础数据类型还有一些补充:
- 数组(array) : 一组相同类型的元素的有序集合。可以指定元素的类型。
typescript
let numbers: number[] = [1, 2, 3];
let strings: string[] = ["apple", "banana", "cherry"];
或者使用泛型来定义数组类型:
typescript
typescript
let anyArray: Array<string> = ["a", "b", "c"];
- 元组(tuple) : 一种特殊的数组,其中的元素可以是不同类型的,并且每个元素都有自己的类型。
typescript
let x: [string, number] = ["hello", 10];
- 枚举(enum) : 定义了一组命名的常量。枚举成员默认从0开始编号,也可以手动指定成员的数值。
typescript
enum Color {Red, Green, Blue}
let color: Color = Color.Green;
- 任意类型(any) : 允许赋值和操作任何类型的数据。
typescript
let anyValue: any = "This is a string";
anyValue = 42; // Now it's a number
- 空值和未定义(void) : 表示没有任何类型。通常用于函数没有返回值的情况。
typescript
function sayHello(): void {
console.log("Hello!");
}
对象类型
依旧是先看图👇:
在ts中的对象类型一般我们可以写一个接口来定义这个对象中每个字段的数据类型,同时也就定义一些规则和这个对象的字段有哪些,然后再将这个接口给到对象上,这里面就涉及到了一些ts的语法: 1. 如图我们可以看到`IBytedancer`的首字母为大写,在ts的编写约定中一般情况下我们书写的类型/接口的名称一般是`首字母大写`,和普通的类或对象区分 2. 如图的sex字段,意思是sex的值只能为那三种的其中一种 3. jobId字段由于设置了只读,意味着后面不能给这个字段更新值,只能在创建的时候赋值
函数类型
函数的声明有两个点:
- 函数每个参数的类型
- 函数返回值的类型
我们声明也可以有两种方法:直接在函数上声明
、写一个接口来声明
看图👇:
数组类型
类型声明方式直接看图👇:
对图片一些解释:
- 看到第二个类型
IArr2
的表示的意思就是这个数组可以出现类型为string
、number
、对象
的元素;Record<string, number>
就是对象的一种写法,泛型中的就表示key和value的类型。 IArr3
表示的是每一个元素的位置要对应上。- 一般我们在声明数组类型的时候可以使用type关键字简化。
typeScript补充类型👇
泛型 泛型就是在定义类型的时候不直接指定一个类型,而是在使用的时候再传入类型;泛型可以有多个
使用方法如下图👇:
类型断言
类型断言是 TypeScript 中的一种机制,允许我们明确地指定一个值的类型。在某些情况下,TypeScript 的类型推断可能无法准确判断变量的类型,或者我们想覆盖编译器的类型推断结果,这时就可以使用类型断言。
类型断言有两种语法:
<Type>expression
(尖括号语法):
typescript
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
expression as Type
(as 关键字语法):
typescript
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
在这两种语法中,Type
是你想要断言的类型,expression
是你想要断言的值。
类型断言的主要用途包括:
- 明确指定变量的类型:当 TypeScript 无法准确推断出变量的类型时,你可以使用类型断言来提供更具体的信息。
- 跳过类型检查:在某些情况下,你可能知道某个值的具体类型,但 TypeScript 编译器无法推断出来。通过类型断言,你可以告诉编译器你已经确认了这个值的类型,从而避免错误的类型检查。
需要注意的是,类型断言并不会改变值的原始类型,它只是在编译阶段
告诉 TypeScript 编译器我们期望这个值具有特定的类型。如果在运行时实际值的类型与断言的类型不匹配,可能会导致运行时错误。
在使用类型断言时应谨慎,过度使用或误用可能会削弱 TypeScript 的类型安全优势。
typeScript高级类型
联合/交叉类型
假设有这样一种场景:有两种类型的数据,不同类型的书籍是根据不同的type来区分的,就像如下图👇:
如图中那样,我们需要编写大量的类型声明的代码,开发就变得繁琐,所以我们就可以把重复的东西提出来,比如例子的`author`,然后使用联合和交叉类型来书写代码,下图为案例的另一种写法👇:
联合类型(Union Types) :
- 联合类型使用
|
符号来表示一个值可以是多种类型之一。 - 当变量被声明为联合类型时,你可以在运行时访问它们的所有类型共有的属性或方法。但是,如果你试图访问非共有属性或方法,TypeScript会在编译时发出错误,这就是类型保护。
访问联合类型时,处于程序安全,仅能访问联合类型中交集的部分
- 类型收缩(Type Narrowing)是处理联合类型的一种重要技巧,通过类型保护或者控制流分析,可以在代码的不同部分确定变量的具体类型。
例如:
typescript
let value: string | number;
value = 'hello'; // 正确
value = 42; // 正确
value.length; // 错误,因为number类型没有length属性
交叉类型(Intersection Types) :
- 交叉类型使用
&
符号来表示一个值必须同时满足多个类型的条件,即合并所有类型的特性。 - 交叉类型的结果是一个新的类型,它包含了所有输入类型的属性和方法。
例如:
typescript
interface A {
a: string;
}
interface B {
b: number;
}
type C = A & B;
let obj: C = {
a: 'hello',
b: 42
};
在这个例子中,C
是一个交叉类型,它要求对象必须同时具有 A
和 B
的属性。
总结起来,联合类型表示一个值可以是几种类型之一,而交叉类型表示一个值必须同时是几种类型。在实际使用中,这两种类型可以帮助你更精确地描述和约束变量的类型,提高代码的可读性和安全性。
keyof关键字
keyof
是 TypeScript 中的一个关键字,用于获取对象类型的键的类型。它返回一个字符串字面量类型或数字字面量类型联合体,这些类型代表了对象的所有可能的键。 以下是一些使用 keyof
关键字的例子:
- 获取对象类型的键类型:
typescript
interface Person {
name: string;
age: number;
}
type PersonKeys = keyof Person; // 等于 "name" | "age"
在这个例子中,PersonKeys
类型是 "name"
和 "age"
的联合类型。
- 使用
keyof
进行类型约束:
typescript
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
let person: Person = { name: 'Alice', age: 30 };
let name: string = getProperty(person, 'name'); // 正确
let age: number = getProperty(person, 'age'); // 正确
let nonExistent: any = getProperty(person, 'nonExistent'); // 错误,'nonExistent' 不是 'Person' 的键
在这个例子中,getProperty
函数接受一个对象和一个键,返回该键对应的值。通过使用 keyof
,我们确保传入的键实际上是对象的合法键。
- 使用
keyof
和映射类型创建新的类型:
typescript
type KeysWithValueType<T, V> = {
[P in keyof T]: T[P] extends V ? P : never;
}[keyof T];
type StringPropertiesOfPerson = KeysWithValueType<Person, string>; // 等于 "name"
在这个例子中,我们创建了一个新的类型 KeysWithValueType
,它接受一个对象类型 T
和一个值类型 V
,并返回一个包含所有其值为 V
的属性名的类型。
总的来说,
keyof
关键字可以帮助我们更精确地处理和操作对象类型的键,使得代码更优雅
函数返回值类型
我们先看一个js的代码:
假设我们要写为ts版本,该怎么操作?
- 首先是函数的入参类型,这个很好理解,就是一个
function
类型 - 然后就是函数的返回值,该怎么定义呢?👇
在预先定义的时候我们可能是不知道这个函数的返回值是什么类型的,所以,我们可以使用前面学过的泛型,所以我们可以这样: