交叉类型
交叉类型表示一个值具有多个类型的属性。它使用&
符号将多个类型组合在一起。下面是一个简单的示例:
typescriptCopy code interface A { a: number; } interface B { b: string; } type AB = A & B; let ab: AB = { a: 42, b: "Hello" }; console.log(ab); // { a: 42, b: "Hello" }
在这个示例中,我们定义了两个接口A
和B
,它们分别定义了a
和b
属性。我们使用交叉类型A & B
创建了一个新类型AB
,它具有a
和b
属性。我们创建了一个对象ab
,它具有a
和b
属性,并将其打印到控制台。
索引类型
索引类型允许我们使用字符串或数字类型的索引来访问对象的属性。它使用[]
符号表示。下面是一个简单的示例:
typescriptCopy code interface Person { name: string; age: number; [key: string]: any; } let person: Person = { name: "Alice", age: 30, address: "123 Main St." }; console.log(person.address); // "123 Main St."
在这个示例中,我们定义了一个名为Person
的接口,它具有name
和age
属性,并使用字符串类型的索引来允许其他任意属性。我们创建了一个名为person
的对象,并为其添加了一个address
属性。我们可以使用person.address
来访问该属性的值。
类型断言
类型断言是 TypeScript 中一种强制类型转换的机制,可以使我们的代码更加灵活、精确和安全。在 TypeScript 中,我们可以使用as
关键字来进行类型断言。
下面是一个简单的示例:
typescriptCopy code const value: unknown = "hello"; const message = (value as string).toUpperCase(); console.log(message); // "HELLO"
在这个示例中,我们定义了一个名为value
的变量,并给它赋值一个字符串。我们使用as
关键字将value
断言为string
类型,并调用toUpperCase
方法,并把它的结果赋值给message
变量。我们输出了message
的值。
可选链操作符
在 JavaScript 中,如果我们访问一个对象的属性,而这个属性不存在,就会返回 undefined
。例如:
javascriptCopy code const person = { name: 'John', age: 30 } console.log(person.job.title) // Uncaught TypeError: Cannot read property 'title' of undefined
在这个例子中,由于 person
对象中没有 job
属性,所以访问 person.job.title
时就会出现错误。
为了避免这种错误,TypeScript 3.7 引入了可选链操作符 ?.
。它可以让我们在访问一个对象的属性时,避免因为属性不存在而导致的错误。例如:
typescriptCopy code const person = { name: 'John', age: 30 } console.log(person.job?.title) // undefined const job = { title: 'Software Engineer' } person.job = job console.log(person.job?.title) // Software Engineer
在第一次使用 person.job?.title
时,由于 person
对象中没有 job
属性,所以直接返回 undefined
,不会报错。
keyof 操作符
keyof
操作符用于获取一个类型的所有属性名称组成的联合类型,它可以使我们的代码更加灵活和可维护。在 TypeScript 中,我们可以使用keyof
操作符来定义泛型类型和访问对象属性。
下面是一个简单的示例:
typescriptCopy code interface Person { name: string; age: number; address: string; } type PersonKeys = keyof Person; // "name" | "age" | "address" function getPropertyValue<T, K extends keyof T>(obj: T, key: K) { return obj[key]; } const person: Person = { name: "Tom", age: 18, address: "Beijing", }; console.log(getPropertyValue(person, "name")); // "Tom" console.log(getPropertyValue(person, "age")); // 18 console.log(getPropertyValue(person, "address")); // "Beijing"
在这个示例中,我们定义了一个Person接口,它包含了name、age和address三个属性。我们使用keyof操作符定义了一个名为PersonKeys的类型,它是Person接口的所有属性名称组成的联合类型。我们定义了一个名为getPropertyValue的函数,它接受一个泛型类型参数T和一个名为K的属性名称参数。在函数内部,我们使用泛型类型参数和keyof操作符来访问对象的属性,并返回属性的值。
装饰器
装饰器是一种特殊的声明,可以附加到类声明、方法、属性或参数上,用来描述类的行为。它们为我们提供了一种简洁明了的方式,以声明式的方式添加或修改类的行为。
装饰器在 TypeScript 中是一个实验性的功能,需要启用experimentalDecorators编译选项。
下面是一个简单的示例:
typescriptCopy code function log(target: any, key: string, descriptor: PropertyDescriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args: any[]) { console.log(`Calling ${key} with args ${args}`); const result = originalMethod.apply(this, args); console.log(`Returned value: ${result}`); return result; }; return descriptor; } class Calculator { @log add(x: number, y: number) { return x + y; } } const calculator = new Calculator(); console.log(calculator.add(2, 3)); // "Calling add with args [2, 3]", "Returned value: 5", 5
在这个示例中,我们定义了一个名为log
的装饰器函数,它接受三个参数:目标类、方法名和方法描述符。我们使用装饰器修饰了Calculator
类中的add
方法,使其在调用时输出日志。我们创建了一个Calculator
实例,并调用了add
方法。
字面量类型
字面量类型是一种特殊的类型,它表示一个确定的值,可以用于增强代码的类型安全性。在 TypeScript 中,我们可以使用字面量类型来定义字符串、数字和布尔值等类型。
下面是一个简单的示例:
typescriptCopy code type Gender = "male" | "female"; interface Person { name: string; age: number; gender: Gender; } const person: Person = { name: "Alice", age: 30, gender: "female" }; console.log(person); // { name: "Alice", age: 30, gender: "female" }
在这个示例中,我们定义了一个名为Gender的字面量类型,它只允许取值"male"或"female"。我们定义了一个名为Person的接口,它具有name、age和gender三个属性,其中gender的类型为Gender。我们创建了一个Person对象,并输出它的值。
类型推断
类型推断是 TypeScript 中一种自动推断类型的机制,可以使我们的代码更加简洁、易读和可维护。在 TypeScript 中,编译器会根据上下文自动推断表达式的类型,并把它们作为类型注解。
下面是一个简单的示例:
typescriptCopy code const message = "hello"; console.log(message.toUpperCase()); // "HELLO"
在这个示例中,我们定义了一个名为message
的常量,并给它赋值一个字符串。我们调用了toUpperCase
方法,并输出了它的结果。TypeScript 编译器会自动推断message
的类型为string
,并把它作为类型注解。
空值和未定义值
在 JavaScript 中,有两种特殊的值,分别是null
和undefined
。在 TypeScript 中,它们分别对应了null
和undefined
两种类型。
下面是一个简单的示例:
typescriptCopy code let x: null = null; let y: undefined = undefined;
在这个示例中,我们定义了两个变量x
和y
,分别赋值为null
和undefined
。
never 类型
never
类型表示那些永远不会发生的值,它可以用于增强代码的类型安全性和可维护性。在 TypeScript 中,never
类型通常用于以下两种情况:
- 当一个函数抛出异常或无限循环时,它的返回类型就是
never
类型。 - 当一个函数返回类型是一个永远不会实现的类型,它的返回类型也是
never
类型。
下面是一个简单的示例:
typescriptCopy code function throwError(message: string): never { throw new Error(message); } function infiniteLoop(): never { while (true) {} }
在这个示例中,我们定义了两个函数,一个是throwError
函数,它接受一个字符串参数message
,并抛出一个错误。另一个是infiniteLoop
函数,它会无限循环。这两个函数的返回类型都是never
类型。
条件类型
条件类型是一种根据一个条件来选择类型的方式,它可以在 TypeScript 中实现一些高级类型操作。在 TypeScript 中,我们可以使用extends
关键字和条件语句来定义条件类型。
下面是一个简单的示例:
typescriptCopy code type IsString<T> = T extends string ? true : false; type Result1 = IsString<string>; // true type Result2 = IsString<number>; // false
在这个示例中,我们定义了一个名为IsString的条件类型,它接受一个泛型类型参数T。如果T类型是字符串类型,则条件类型的结果为true,否则为false。我们还定义了两个变量Result1和Result2,它们分别是IsString<string>和IsString<number>类型的结果。