TypeScript学习记录

62 阅读7分钟

声明空间

类型注解内容

class Foo {}
interface Bar {}
type Bas = {};

//作为类型声明
let foo: Foo;
let bar: Bar;
let bas: Bas;

//但是不可以直接将这个声明作为变量使用

尽量不要使用全局变量空间,可能会与文件内的代码命名冲突,不过可以通过文件模块去定义 即使用export,采用导出、导入的方式来完成。

模块

const someVar = 123;
type someType = {
  type: string;
};

export { someVar, someType };

import { someVar, someType } from './foo';

类型系统

基本类型

使用:TypeAnnotation语法,在类型声明空间可用的内容都可以用作类型注解

const num: number = 123;
function identity(num: number): number {
  return num;
}

*JavaScript原始类型也同样适用typeScript的类型系统(String、number、boolean均可被用作类型注解),数组也同样可以被提供类型

let num: number;
let str: string;
let bool: boolean;

let boolArray: boolean[];

接口

类似一个对象,将多个数据类型注解合并为一个类型声明(有点类似后端中的Model类)

interface Name {
  first: string;
  second: string;
}

内联类型注解

可以理解为将接口与基本类型的写法合在一起

let name: {
  first: string;
  second: string;
};

特殊类型

let power: any;

//注:在类型系统中,JavaScript 中的 null 和 undefined 字面量和其他被标注了 `any` 类型的变量一样,都能被赋值给任意类型的变量

泛型

通常在开发过程中,有时候返回类型会发生变化,但是仍然需要添加一些约束,允许在定义函数、类、接口等时使用类型参数,使得这些结构能够适用于多种类型而不是固定于一种类型

// 泛型函数示例
function echo<T>(value: T): T {
    return value;
}

// 使用泛型函数
let result1: number = echo<number>(42); // 指定泛型参数为 number
let result2: string = echo<string>("Hello, Generics!"); // 指定泛型参数为 string

// 泛型类示例
class Box<T> {
    private value: T;

    constructor(value: T) {
        this.value = value;
    }

    getValue(): T {
        return this.value;
    }
}

// 使用泛型类
let numberBox = new Box<number>(123); // 指定泛型参数为 number
let stringBox = new Box<string>("Generics"); // 指定泛型参数为 string

console.log(numberBox.getValue()); // 输出: 123
console.log(stringBox.getValue()); // 输出: Generics

泛型不仅仅是取返回值作为类型,更加准确的说,泛型是一种参数化类型机制。允许编写具有灵活类型的代码,不必提前指定具体类型。当创建一个使用泛型的函数、类或接口时,你可以在使用时指定具体的类型。这使得这些结构可以适用于各种类型的数据,而不是固定在某一种类型上。

function identity<T>(arg: T): T {
    return arg;
}

// 使用泛型函数
let output = identity<string>("hello");
// 在这个例子中,T 被指定为 string 类型,所以输出变量 output 的类型也是 string。

let output2 = identity<number>(42);
// 在这个例子中,T 被指定为 number 类型,所以输出变量 output2 的类型也是 number。

//即可以在使用时候根据需要的类型来自己进行设置或者选择

联合类型

可以表示这个变量可以为多种类型之一的类型;使用'|'符号将多种类型排列在一起,表示变量可以是其中的一种类型

function printId(id: string | number) {
    console.log(id);
}

printId("abc");   // 合法
printId(123);     // 合法
// printId(true);  // 错误,布尔类型不是 string 或 number 中的一种

交叉类型

多个类型合并为一个新类型,使用交叉类型时候,可以使用'&'符号将多个类型合并在一起

interface Person {
    name: string;
    age: number;
}

interface Employee {
    jobTitle: string;
    salary: number;
}

type PersonEmployee = Person & Employee; let employee: PersonEmployee = { name: "John", age: 30, jobTitle: "Software Developer", salary: 50000 };

元组类型

一种特殊类型,它允许你定义一个固定长度和每个元素类型都明确的数组(本人觉得,不太好用,不如直接使用any,但是在特定场景可能还是会使用到)

let tuple: [string, number, boolean];

tuple[0] = "hello";
tuple[1] = 42;
tuple[2] = true;

// 获取元素
let str: string = tuple[0];
let num: number = tuple[1];
let bool: boolean = tuple[2];

注意事项

  • 所有的JavaScript代码都是有效的TypeScript代码,就是如果使用Ts编译Js,结果会与原始的js代码一样,就是说,直接把js文件修改为ts文件是不会造成影响的。
  • 在代码中,尽量少的使用any
  • 关于declare,该关键字通常在Ts中告诉编译器某个定义的字段的类型,但是就这一块代码,是不会在最终的Js代码中生成实际的声明或者代码,即:它用于声明一个全局变量,但是并不创建实际的变量,而是告诉编译器该变量已经在其他地方声明过了,这样做的目的是为了避免Ts编译报错,因为某些全局变量可能是在别的文件或者库中已经定义的。

枚举类型

在ts中,枚举类型可以是数字,字符串类型,默认情况下枚举成员被赋予数字值,从0开始递增

//默认情况
enum Color {
  Red,    // 0
  Green,  // 1
  Blue    // 2
}

//手动设置
enum Color { 
    Red = 1, 
    Green = 2, 
    Blue = 4 
}

//String类型
enum Direction { 
    Up = "UP", 
    Down = "DOWN", 
    Left = "LEFT", 
    Right = "RIGHT" 
}

//对象类型
enum Direction {
  Up = { x: 0, y: -1 },
  Down = { x: 0, y: 1 },
  Left = { x: -1, y: 0 },
  Right = { x: 1, y: 0 }
}

有静态方法的枚举类

enum Weekday {
  Monday,
  Tuesday,
  Wednesday,
  Thursday,
  Friday,
  Saturday,
  Sunday
}

namespace Weekday {
  export function isBusinessDay(day: Weekday) {
    switch (day) {
      case Weekday.Saturday:
      case Weekday.Sunday:
        return false;
      default:
        return true;
    }
  }
}

const mon = Weekday.Monday;
const sun = Weekday.Sunday;

console.log(Weekday.isBusinessDay(mon)); // true
console.log(Weekday.isBusinessDay(sun));

//示例中,看起来是定义了一个枚举类Weekday,并通过使用nameSpace来扩展了枚举类的命名空间,然后在这个空间中定义了一个静态方法。这是Ts的一种模块化方式,有助于防止全局作用域中的命名冲突,更易于代码的维护和理解。不过最新的Ts中,推荐使用ES6的模块系统(import 与 export)来替代
//需要注意的是,枚举类本身就是一个对象,枚举成员可以包含值和方法
//*枚举成员不能包涵实例属性,因为他们只是一组命名的常量值

//在Ts中,如果对同一作用域尝试对现有的枚举类添加新的成员,这些成员值如果不冲突的话,是可以的,
enum Color {
  Red,
  Green,
  Blue
}

enum Color {
  DarkRed = 3,
  DarkGreen,
  DarkBlue
}

console.log(Color.Red);        // 0
console.log(Color.DarkRed);    // 3
console.log(Color.Green);      // 1
console.log(Color.DarkGreen);  // 4
console.log(Color.Blue);       // 2
console.log(Color.DarkBlue);   // 5

类型断言

Ts允许覆盖推断,并且能够以自己想要的方式分析,这种机制被称为类型断言

内置的泛型工具类型

TypeScript 提供了许多内置的泛型工具类型,以下是一些常见的 TypeScript 内置泛型工具类型:

  1. Readonly<T> 将类型 T 中的所有属性变只读选属性。

    typescriptCopy code
    type PartialFoo = Readonly<Foo>;
    
  2. Partial<T> 将类型 T 中的所有属性变为可选属性。

    typescriptCopy code
    type PartialFoo = Partial<Foo>;
    
  3. Required<T> 将类型 T 中的所有属性变为必选属性。

    typescriptCopy code
    type RequiredFoo = Required<Foo>;
    
  4. Pick<T, K> 从类型 T 中选择一组属性 K 形成新类型。

    typescriptCopy code
    type PickFoo = Pick<Foo, 'bar'>; // 选择 'bar' 属性
    
  5. Record<K, T> 创建一个具有键 K 类型,值为 T 类型的对象。

    typescriptCopy code
    type RecordFoo = Record<'newKey', number>;
    
  6. Omit<T, K> 从类型 T 中排除一组属性 K 形成新类型。

    typescriptCopy code
    type OmitFoo = Omit<Foo, 'bar'>; // 排除 'bar' 属性
    
  7. Exclude<T, U> 从类型 T 中排除可以赋值给类型 U 的所有属性。

    typescriptCopy code
    type Excluded = Exclude<number | string, string>; // 选择 number 类型
    
  8. Extract<T, U> 从类型 T 中选择可以赋值给类型 U 的所有属性。

    typescriptCopy code
    type Extracted = Extract<number | string, number>; // 选择 number 类型
    
  9. NonNullable<T> 从类型 T 中排除 nullundefined

    typescriptCopy code
    type NonNullableFoo = NonNullable<string | null | undefined>; // 选择 string 类型
    

这里只是一部分内置的类型工具,还有更多的类型可以参考一下官网的文档:# Utility Types 。。。(待续更)