高级类型
交叉类型和联合类型
TypeScript中的交叉类型(Intersection Types)和联合类型(Union Types)是两种不同的类型组合方式。
交叉类型用符号“&”表示,可以将多个类型合并为一个类型,这个类型包含了所有被合并类型的成员。例如,如果有两个类型A和B,那么A & B表示同时具有A和B的所有成员。例如:
interface Dog {
name: string;
bark(): void;
}
interface Cat {
name: string;
meow(): void;
}
type DogCat = Dog & Cat;
const pet: DogCat = {
name: 'Fido',
bark: () => console.log('Woof!'),
meow: () => console.log('Meow!')
};
在上面的例子中,DogCat类型包含了Dog和Cat类型的所有成员,因此我们可以创建一个具有name、bark和meow成员的对象。
联合类型用符号“|”表示,可以将多个类型组合起来,表示这些类型中的任何一个都是合法的类型。例如,如果有两个类型A和B,那么A | B表示A或B中的任何一个类型都是合法的。例如:
type StringOrNumber = string | number;
function printValue(value: StringOrNumber) {
console.log(`The value is ${value}`);
}
printValue('hello');
printValue(42);
在上面的例子中,StringOrNumber类型可以是字符串或数字,因此我们可以将字符串’hello’和数字42传递给printValue函数。
类型别名和字符串字面量类型
TypeScript中的类型别名(Type Aliases)允许为一个已有的类型起一个新的名字。这个新的名字可以被用于任何原先使用原始类型的地方。语法如下:
type NewTypeName = ExistingType
例如,可以使用类型别名来定义一个字符串类型,如下所示:
type MyString = string;
字符串字面量类型是一种特殊的类型,它允许你指定字符串只能取某些固定的值。使用字符串字面量类型可以提高代码的可读性和可维护性。语法如下:
type LiteralType = 'value1' | 'value2' | ... | 'valueN';
例如,可以使用字符串字面量类型来定义一个表示颜色的类型,如下所示:
type Color = 'red' | 'green' | 'blue';
在定义变量或函数参数时,可以使用上述定义的字符串字面量类型,如下所示:
let backgroundColor: Color = 'red';
function setTextColor(color: Color): void {
// ...
}
可辨识联合和类型守卫
可辨识联合是一种特殊的联合类型,它包含一个具有单一属性的类型成员,称为可辨识的特征。类型守卫是一种在运行时检查变量类型的技术,可以使用 typeof、instanceof、in 等操作符进行类型判断。以下是示例代码:
可辨识联合:
interface Square {
kind: 'square';
size: number;
}
interface Rectangle {
kind: 'rectangle';
width: number;
height: number;
}
type Shape = Square | Rectangle;
function area(shape: Shape) {
switch (shape.kind) {
case 'square':
return shape.size * shape.size;
case 'rectangle':
return shape.width * shape.height;
}
}
const square: Square = { kind: 'square', size: 5 };
const rectangle: Rectangle = { kind: 'rectangle', width: 2, height: 3 };
console.log(area(square)); // 25
console.log(area(rectangle)); // 6
类型守卫:
interface Cat {
name: string;
meow(): void;
}
interface Dog {
name: string;
bark(): void;
}
function makeSound(animal: Cat | Dog) {
if ('meow' in animal) {
animal.meow();
} else {
animal.bark();
}
}
const cat: Cat = { name: 'Kitty', meow: () => console.log('Meow!') };
const dog: Dog = { name: 'Buddy', bark: () => console.log('Woof!') };
makeSound(cat); // Meow!
makeSound(dog); // Woof!
索引类型和映射类型
TypeScript 中的索引类型和映射类型都是高级类型,用于表示某些特定的数据结构和数据操作。
索引类型允许我们使用一个字符串或数字类型的值来访问另一个类型中对应的属性或元素。在 TypeScript 中,可以使用索引类型来表示对象、数组等数据结构的访问方式。例如,可以定义一个具有任意键值对的对象类型:
type Dict = {
[key: string]: any;
};
这里 [key: string]: any
表示该类型可以有任意数量的字符串键,并且对应的值类型为 any
。
另一方面,映射类型则允许我们将一个类型中的每个属性进行某种变换。其中最常见的是 Partial
和 Readonly
映射类型,分别用于将一个类型中的所有属性设置为可选和只读。例如:
interface Person {
name: string;
age: number;
}
type PartialPerson = Partial<Person>;
// 等价于:{ name?: string; age?: number; }
type ReadonlyPerson = Readonly<Person>;
// 等价于:{ readonly name: string; readonly age: number; }
除了内置的 Partial
和 Readonly
类型之外,还可以自定义映射类型。例如,以下代码定义了一个将一个类型中所有字符串属性添加 readonly
修饰符的映射类型:
type ReadonlyStringProps<T> = {
readonly [P in keyof T & string]: T[P];
};
interface Person {
name: string;
age: number;
}
type ReadonlyPerson = ReadonlyStringProps<Person>;
// 等价于:{ readonly name: string; age: number; }
在上面的代码中,keyof T & string
表示只匹配 T
中的字符串属性。然后使用 [P in keyof T & string]
循环遍历每个字符串属性,并将它们添加 readonly
修饰符。
tsconfig.json介绍
tsconfig.json文件是TypeScript编译器的配置文件,用于指定编译时的选项和参数。以下是各个选项的解释:
-
compilerOptions
:编译选项的配置,包含了大量控制 TypeScript 如何编译代码的设置。target
:指定编译后的 JavaScript 代码目标运行环境的版本,默认值为 ES3。module
:指定生成的模块化代码规范,例如 CommonJS 或 ES6 模块化等。outDir
:指定编译输出目录的路径。sourceMap
:指示是否为每个输出文件生成一个 source map 文件,以便在调试时可以追踪到原始 TypeScript 代码。strict
:是否启用严格类型检查。noImplicitAny
:指示是否禁止隐式 any 类型。esModuleInterop
:是否允许使用 esModuleInterop 转换导入。allowJs
:是否允许编译 JavaScript 文件。declaration
:是否生成声明文件(d.ts)。declarationDir
:生成声明文件的目录路径。jsx
:设置 JSX 的类型,可选值为"preserve"
、"react"
和"react-native"
。
-
include
和exclude
:指定哪些文件应该被编译或排除在编译之外。 -
files
:指定编译时应包含的文件列表,如果使用了files
,则include
和exclude
将被忽略。 -
references
:指定一个或多个项目依赖关系。
tsconfig.json示例
{
"compilerOptions": {
/* Basic Options */
"target": "es5", /* 目标ECMAScript版本 */
"module": "commonjs", /* 模块系统 */
"lib": ["es6", "dom"], /* 编译时包含的库 */
"allowJs": true, /* 允许编译JS文件 */
"checkJs": true, /* 在JS文件中启用类型检查 */
"jsx": "react", /* 启用React JSX支持 */
"declaration": true, /* 自动生成.d.ts声明文件 */
"sourceMap": true, /* 生成源映射文件 *.map */
"outDir": "./dist", /* 编译输出目录 */
"removeComments": true, /* 去除注释 */
"strict": true, /* 启用所有严格类型检查选项 */
/* Additional Checks */
"noUnusedLocals": true, /* 检测未使用的局部变量 */
"noUnusedParameters": true, /* 检测未使用的函数参数 */
"noImplicitReturns": true, /* 检测缺少返回类型的函数 */
"noFallthroughCasesInSwitch": true, /* 检测switch语句中的缺失break或return */
/* Advanced Options */
"experimentalDecorators": true, /* 启用装饰器语法支持 */
"emitDecoratorMetadata": true, /* 生成元数据,以便在反射API中使用 */
"esModuleInterop": true, /* 允许使用CommonJS和ES模块之间的互操作性 */
"allowSyntheticDefaultImports": true, /* 允许从没有默认导出的模块中默认导入 */
"forceConsistentCasingInFileNames": true /* 强制文件名大小写一致 */
},
"include": ["src/**/*"], /* 指定需要编译的源文件或目录 */
"exclude": ["node_modules", "dist"] /* 排除不需要编译的文件或目录 */
}