文章目录
- 使用技巧
- TypeScript内置的工具类型
- keyof
- extends 限定泛型
- interface 与 type 区别
TypeScript作为JavaScript的超集,通过提供静态类型系统和对ES6+新特性的支持,使JavaScript开发变得更加高效和可维护。掌握TypeScript的使用技巧,可以帮助我们更好地开发和组织JavaScript项目。刚开始用的时候感觉好多限制,特别是配置静态类型检测后就容易各种报错,恨不得都用any, 那岂不是成了AnyScript,不过熟能生巧,用得多了就会爱上这个语言。这里总结了一些平时用到ts技巧。
使用技巧
当使用TypeScript进行开发时,有一些常用的技巧可以帮助你提高代码质量和开发效率。以下是一些TypeScript使用技巧:
-
类型注解和类型推断:尽量为变量、函数参数、函数返回值等添加类型注解,以增加代码的可读性和类型安全性。同时,TypeScript也会自动推断很多类型,充分利用类型推断特性。
-
使用接口和类型别名:使用接口和类型别名来定义自定义类型,使代码更具表达力和清晰度。
// 使用接口
interface Person {
name: string;
age: number;
}
// 使用类型别名
type Point = { x: number; y: number };
- 泛型:使用泛型来增加代码的灵活性,使函数和类能够处理多种类型的数据。
function toArray<T>(value: T): T[] {
return [value];
}
- 枚举:使用枚举来定义一组具有名字的常量值,提高代码可读性。
enum Color {
Red,
Green,
Blue,
}
- 非空断言和可选链:使用非空断言(!)来告诉编译器一个值一定不为null或undefined,使用可选链(?.)来简化处理可能为null或undefined的属性和方法。
const name: string = maybeName!; // 非空断言
const age = person?.age; // 可选链
- 确定赋值断言:在声明变量时使用确定赋值断言(!)来告诉编译器该变量一定会在使用前被赋值。
let value!: number;
TypeScript内置的工具类型
当使用 TypeScript 进行开发时,有一些常用的类型工具(utility types)可以帮助你更好地处理类型,并提高代码质量和开发效率。下面是对 Partial
、Record
、Pick
、Omit
、Exclude
和 Parameters
这些类型工具的中文详细解释:
-
Partial<Type>
(部分类型):Partial
是 TypeScript 内置的一个类型工具,用于使给定类型的所有属性变为可选属性。- 它创建了一个新的类型,其中给定类型
Type
的所有属性都变成了可选属性。 - 示例:
interface Person { name: string; age: number; } type PartialPerson = Partial<Person>; // 等同于: // interface PartialPerson { // name?: string; // age?: number; // }
-
Record<Key, Type>
(记录类型):Record
是 TypeScript 内置的类型工具,用于创建一个由指定键和给定值类型组成的对象类型。- 它接受两个类型参数
Key
和Type
,并创建一个对象类型,其中每个属性的键是类型Key
,值是类型Type
。 - 示例:
type AgeMap = Record<string, number>; // 等同于: // interface AgeMap { // [key: string]: number; // }
-
Pick<Type, Keys>
(挑选类型):Pick
是 TypeScript 内置的类型工具,用于从给定类型中挑选出特定的属性形成新的类型。- 它接受两个类型参数
Type
和Keys
,并创建一个新的类型,其中只包含类型Type
中由Keys
指定的属性。 - 示例:
interface Person { name: string; age: number; address: string; } type PersonNameAndAge = Pick<Person, "name" | "age">; // 等同于: // interface PersonNameAndAge { // name: string; // age: number; // }
-
Omit<Type, Keys>
(省略类型):Omit
是 TypeScript 内置的类型工具,用于从给定类型中省略特定的属性形成新的类型。- 它接受两个类型参数
Type
和Keys
,并创建一个新的类型,其中包含了类型Type
中除了Keys
指定的属性以外的所有属性。 - 示例:
interface Person { name: string; age: number; address: string; } type PersonWithoutAddress = Omit<Person, "address">; // 等同于: // interface PersonWithoutAddress { // name: string; // age: number; // }
-
Exclude<Type, ExcludedUnion>
(排除类型):Exclude
是 TypeScript 内置的类型工具,用于从给定类型中排除可以赋值给ExcludedUnion
的成员。- 它接受两个类型参数
Type
和ExcludedUnion
,并创建一个新的类型,其中只包含类型Type
中不可赋值给ExcludedUnion
的成员。 - 示例:
type MyNumbers = number | string | boolean; type OnlyNumbers = Exclude<MyNumbers, string | boolean>; // 等同于: // type OnlyNumbers = number;
-
Parameters<Type>
(函数参数类型):Parameters
是 TypeScript 内置的类型工具,用于从给定函数类型中提取出参数的类型。- 它接受一个函数类型
Type
作为参数,并返回一个由该函数的参数类型组成的元组类型。 - 示例:
type MyFunction = (name: string, age: number) => void; type FunctionParameters = Parameters<MyFunction>; // 等同于: // type FunctionParameters = [string, number];
keyof
在 TypeScript 中,keyof
是一个关键字和类型操作符,它用于获取一个类型的所有属性名组成的联合类型。keyof
可以结合泛型、索引类型等特性来实现许多有用的类型操作。
使用 keyof
的语法是 keyof Type
,其中 Type
是一个类型。它返回一个联合类型,包含了 Type
类型中所有属性的名称。这个联合类型可以用来访问或操作 Type
类型中的属性。keyof 与 Object.keys 略有相似,只不过 keyof 取 interface 的键。
下面是一个简单的示例代码:
interface Person {
name: string;
age: number;
gender: string;
}
type PersonKey = keyof Person;
// 等同于:type PersonKey = "name" | "age" | "gender"
在这个例子中,keyof Person
返回一个联合类型,包含了 Person
类型中所有属性的名称。结果类型是 "name" | "age" | "gender"
。
keyof
可以与其他 TypeScript 特性结合使用,例如:
- 通过索引类型访问对象属性:
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
const person: Person = { name: "Alice", age: 30, gender: "female" };
const name = getProperty(person, "name"); // name的类型是string
- 确定属性是否存在:
function hasProperty<T, K extends keyof T>(obj: T, key: K): boolean {
return key in obj;
}
const hasAge = hasProperty(person, "age"); // hasAge的值是true
const hasEmail = hasProperty(person, "email"); // hasEmail的值是false
extends 限定泛型
在 TypeScript 中,可以使用 extends
关键字来限定泛型类型的范围,确保传入的泛型参数满足一定的条件。这种方式称为"泛型约束"或"泛型限定"。通过泛型约束,我们可以对泛型进行更精确的类型检查,提高代码的类型安全性。
下面是几个使用 extends
关键字限定泛型的例子:
- 简单的泛型约束:
function printProperty<T extends { name: string }>(obj: T) {
console.log(obj.name);
}
printProperty({ name: "Alice", age: 30 }); // OK
printProperty({ age: 30 }); // Error: 缺少name属性
在这个例子中,使用 extends { name: string }
来限定泛型 T
必须具有一个 name
属性,否则会在调用时报错。
- 使用多个泛型约束:
function combine<T extends string, U extends string>(a: T, b: U): string {
return a + b;
}
const result = combine("Hello, ", "TypeScript"); // result的值是 "Hello, TypeScript"
在这个例子中,使用 extends string
来限定泛型 T
和 U
必须是 string
类型,确保只有 string
类型的参数可以传入函数 combine
中。
- 使用接口约束泛型:
interface Lengthwise {
length: number;
}
function printLength<T extends Lengthwise>(obj: T) {
console.log(obj.length);
}
printLength("Hello"); // 输出: 5
printLength([1, 2, 3]); // 输出: 3
在这个例子中,使用 extends Lengthwise
来限定泛型 T
必须满足 Lengthwise
接口,即必须有一个 length
属性。
interface 与 type 区别
在 TypeScript 中,interface
和 type
是两种用来定义类型的方式,它们有一些相似之处,但也有一些不同之处。下面是它们的区别:
-
interface
:interface
是用来描述对象的形状的类型声明。- 它可以用来定义对象的结构,包含属性、方法和索引签名等。
interface
可以被合并,当多次定义同名的interface
时,它们会自动合并为一个。
interface Person { name: string; age: number; } interface Person { gender: string; } // 合并后等同于: // interface Person { // name: string; // age: number; // gender: string; // }
-
type
:type
是用来定义任意类型的类型别名。- 它可以用来定义原始类型、联合类型、交叉类型、函数类型等。
type
不能被合并,当多次定义同名的type
时,会报错。- 要合并需要用
&
连接
type Age = number; type Gender = "male" | "female"; type Person = { name: string; age: Age; gender: Gender; }; type both = Person & Age // 这样将两个类型合并成一个
-
使用场景:
interface
通常用于描述对象的结构,它更适合用于定义对象和类的类型。type
可以定义更复杂的类型,包括联合类型、交叉类型和函数类型等,它更适合用于定义临时的类型别名。