TypeScript 高级数据类型 | 青训营笔记

32 阅读6分钟

这是我参与「第五届青训营 」笔记创作活动的第8天

一、本堂课重点内容:

  1. 联合交叉类型
  2. 类型保护与类型守卫
  3. Merge 函数类型实现
  4. 函数返回值类型
  5. TypeScript 工程应用

二、详细知识点介绍:

TypeScript进阶语法

  1. 联合/交叉类型: TypeScript支持联合类型和交叉类型,联合类型是使用 | 运算符将多个类型组合在一起,而交叉类型是使用 & 运算符将多个类型组合在一起。
type A = {a: number}
type B = {b: string}
let AB: A | B = {a: 1}
let AandB: A & B = {a: 1, b: 'string'}
  1. 类型保护与类型守卫: TypeScript支持类型保护和类型守卫,类型保护是指在运行时使用特定的逻辑来确定变量的类型,而类型守卫是指在编译时使用特定的逻辑来确定变量的类型。

    function isFish(pet: Fish | Dog): pet is Fish {
        return (pet as Fish).swim !== undefined;
    }
    if (isFish(pet)) {
        pet.swim();
    } else {
        pet.bark();
    }
    

    这段 TypeScript 代码定义了一个名为 isFish 的函数,它接收一个参数 pet,它的类型为 Fish 或 Dog 中的一种。

    函数 isFish 定义了一个类型保护,使用了 TypeScript 的 "类型断言" 语法来判断 pet 参数是否是 Fish 类型。如果参数 pet 有 swim 属性,就说明它是 Fish 类型,返回 true。否则返回 false。

    在 if 语句中,通过调用 isFish 函数来判断 pet 的类型,如果是 Fish 类型,则调用 pet.swim() 方法,如果是 Dog 类型,则调用 pet.bark() 方法。

  2. 高级类型: TypeScript支持一些高级类型,如索引类型、条件类型、自定义运算符类型等。

  • 索引类型: TypeScript 支持使用 keyof 和索引类型查询类型,可以获取对象属性名的类型
interface Person {
  name: string;
  age: number;
}
type PersonKey = keyof Person; // "name" | "age"
  • 条件类型: TypeScript 支持条件类型,可以根据条件判断类型

    type TypeName<T> = T extends string
      ? "string"
      : T extends number
      ? "number"
      : T extends boolean
      ? "boolean"
      : T extends undefined
      ? "undefined"
      : T extends Function
      ? "function"
      : "object";
    

    这段 TypeScript 代码定义了一个名为 TypeName 的泛型类型别名。它接收一个类型参数 T,并通过条件类型运算符 (T extends X ? Y : Z) 来判断 T 的类型。

    当 T 是 string 类型时,TypeName 的类型为 "string"。当 T 是 number 类型时,TypeName 的类型为 "number"。同理,当 T 是 boolean、undefined、Function 时,TypeName 的类型分别为 "boolean"、"undefined"、"function"。如果 T 不是上述类型之一,那么 TypeName 的类型为 "object"。

    这个类型别名可以用来在程序中获取变量的类型名称,或者在类型之间进行类型比较。例如,可以使用 TypeName 来判断一个变量是否是字符串类型。

  • 自定义运算符类型: TypeScript 支持自定义运算符类型,可以使用自定义运算符类型来描述类型

type Nullable<T> = T | null;
type NotNullable<T> = T extends null ? never : T;

4.函数返回值类型:

TypeScript 支持使用 never 类型来表示函数永远不会返回值,可以使用never类型来描述函数返回值类型

function throwError(message: string): never {
    throw new Error(message);
}

"=>" 是 TypeScript 中用来定义函数类型的箭头符号。它可以被用来定义函数的参数类型和返回值类型。

举个例子:

let add: (x: number, y: number) => number = function(x: number, y: number): number {
    return x + y;
}

上面的代码中,我们使用 "=>" 来定义了一个 add 函数,它接受两个 number 类型的参数 x 和 y,并返回一个 number 类型的结果。

在 TypeScript 中,这种类型的函数被称为箭头函数。

其实还有另一种简写的写法

let add = (x: number, y: number) => x + y

在上面的代码中,我们可以看到,函数体只有一条语句,并且是一个返回值,所以可以这样简写。

总之, "=>" 可以用来简洁地定义函数的类型,并且更易于阅读和理解。

TypeScript工程应用

image.png

相关loader:

  1. awesome-typescript-loader
  2. babel-loader

image.png

在 NodeJs 应用中,TypeScript需要使用 TSC (TypeScript Compiler) 编译成 JavaScript。 TSC 是 TypeScript 的命令行工具,可以将 TypeScript 编译成 JavaScript。 命令行使用:

tsc --outDir dist --rootDir src src/index.ts

在工程应用中,使用 TypeScript 需要先安装 TypeScript 依赖包和配置 TypeScript 配置文件 (tsconfig.json)。配置文件中可以设置编译选项、文件路径等。

三、实践练习例子:

  1. ?的意义: 在 TypeScript 中, ? 表示可选属性。
interface SquareConfig {
    color?: string;
    width?: number;
}
let obj: SquareConfig = {};
obj.color = 'red';

这段代码定义了一个接口 SquareConfig,它包含了两个可选属性 color 和 width。

接着定义了一个变量 obj,它的类型是 SquareConfig。然后赋值为一个空对象{}。

最后,在obj对象上添加了一个color属性,并赋值为'red'。

这段代码简单的演示了如何使用接口来定义对象的类型。接口 SquareConfig 定义了对象应该具有的属性,并且这些属性都是可选的。通过定义 obj 的类型为 SquareConfig,我们可以确保 obj 对象只具有 SquareConfig 接口中定义的属性。

  1. extends/infer的注意事项

image.png

四、课后个人总结:

学习 TypeScript 过程中,我发现联合类型和交叉类型是最难理解的部分。虽然它们是非常有用的特性,但是理解起来有些困难。我也发现,当我尝试在代码中使用它们时,很容易将它们与其他类型混淆。类型保护和类型守卫是我学习的另一个难点。它们是实现类型转换的关键,但是它们的实现方式有点复杂。我认为,这部分内容需要更多的练习和实践才能更好地理解。在函数类型实现中,我发现了 Merge 函数的用法。它是一个非常有用的函数,能够帮助我们合并两个对象的属性,但是我认为它的用法有些复杂,需要更多的练习才能熟练掌握。在函数返回值类型中,我学习了如何使用 "=>" 来定义函数的返回值类型。这是一个非常有用的特性,能够帮助我们更好地管理函数的返回值。在实例部分,我们练习了如何使用 "?" 来定义可选属性和使用 "extends" 和 "infer" 来实现泛型和类型推断。我发现,这些特性能够帮助我们更好地管理类型和提高代码的可读性。

总的来说,学习 TypeScript 是一个非常有益的经历。它是一种非常强大的语言,能够帮助我们更好地编写和管理代码。

五、引用参考:

TypeScript 高级数据类型