TypeScript基础学习

一、简介

1、什么是TypeScript

TypeScriptJavaScript的超集,继承的基础上扩展了JavaScript,它可以实现强类型,静态类型检查的一门语言

2、为什么需要TypeScript

简单来说就是因为JavaScript是弱类型的动态类型语言, 很多错误只有在运行时才会被发现
TypeScript提供了一套静态检测机制, 可以帮助我们在编译时就发现错误

3、TypeScript特点
  • 支持最新的JavaScript特性
  • 支持代码静态检查
  • 支持诸如C,C++,Java,Go等后端语言中的特性 (枚举、泛型、类型转换、命名空间、声明文件、类、接口等)

二、简单使用

1、全局安装typescript
npm i -g typescript
2、新建test1.ts文件
let num:number = 100
num = 200
3、执行 tsc test1.ts命令将ts文件转换为js文件

三、基础数据类型

JS的八种内置类型,七种原始类似:Boolean、Null、Undefined、Number、BigInt、String、SymbolObject

let str: string = "jimmy";
let num: number = 24;
let bool: boolean = false;
let u: undefined = undefined;
let n: null = null;
let obj: object = {x: 1};
let big: bigint = 100n;
let sym: symbol = Symbol("me"); 

注意点:1、默认情况下 null 和 undefined 是所有类型的子类型。 就是说你可以把 null 和 undefined 赋值给其他类型。2、虽然number和bigint都表示数字,但是这两个类型不兼容。

四、其他类型

1、Array(数组)
  • 对数组类型的定义有两种方式:
let arr:string[] = ["1","2"];
let arr2:Array<string> = ["1","2"]
  • 定义联合类型数组
let arr:(number | string)[];
// 表示定义了一个名称叫做arr的数组, 
// 这个数组中将来既可以存储数值类型的数据, 也可以存储字符串类型的数据
arr3 = [1, 'b', 2, 'c'];
  • 定义指定对象成员的数组:
// interface是接口,后面会讲到
interface ArrObj{
    name:string,
    age:number
}
let arr3:ArrObj[]=[{name:'jimmy', age:22}]
2、Tuple(元组)

数组一般由同种类型的值组成,但有时我们需要在单个变量中存储不同类型的值,这时候我们就可以使用元组。在 JavaScript 中是没有元组的,元组是 TypeScript 中特有的类型,其工作方式类似于数组。
元组最重要的特性是可以限制数组元素的个数和类型,它特别适合用来实现多值返回。

let x: [string, number]; 
// 类型必须匹配且个数必须为2

x = ['hello', 10]; // OK 
x = ['hello', 10,10]; // Error 
x = [10, 'hello']; // Error
3、Enum 类型

使用枚举我们可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。 TypeScript 支持数字的和基于字符串的枚举。

enum Direction {
  NORTH,
  SOUTH,
  EAST,
  WEST,
}
let dir: Direction = Direction.NORTH;

默认情况下,NORTH 的初始值为 0,其余的成员会从 1 开始自动增长。换句话说,Direction.SOUTH 的值为 1,Direction.EAST 的值为 2,Direction.WEST 的值为 3

五、Interfaces(接口)

TypeScript 中的接口是一个非常灵活的概念,除了可用于对类的一部分行为进行抽象以外,也常用于对**「对象的形状(Shape)」**进行描述。

  • 1、对象的形状
interface Person {
  name: string;
  age: number;
}
let Semlinker: Person = {
  name: "Semlinker",
  age: 33,
};

// 定义的变量比接口少了一些属性是不允许的,多一些属性也是不允许的
let tom: Person = {
    name: 'Tom'
};
// error TS2322: Type '{ name: string; }' is not assignable to type 'Person'.
//   Property 'age' is missing in type '{ name: string; }'.
  • 2、只读 | 可选属性
interface Person {
  readonly name: string; // 只读属性。定义属性值后不能重新赋值
  age?: number;  // 可选属性,定义时可以不定义这个属性也不会报错
}

六、函数

  • 1、函数声明
function sum(x: number, y: number): number {
    return x + y;
}
  • 2、函数表达式
let mySum: (x: number, y: number) => number = sum  // 和上面的sum函数一样

注意点:上面的 => number是设定函数的返回值,而不是ES6中的箭头函数中的参数

  • 3、用接口描述来函数类型(描述函数的参数类型和返回值类型)
interface ISum{
  (x: number, y: number): number;
}
let add2: ISum = sum
  • 4、可选参数
    加上 号,可选参数后面不能还有非可选参数
function buildName(firstName: string, lastName?: string) {
    if (lastName) {
        return firstName + ' ' + lastName;
    } else {
        return firstName;
    }
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
  • 5、参数默认值
function buildName(firstName: string, lastName: string = 'Cat') {
    return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
  • 6、剩余参数
function push(array: any[], ...items: any[]) {
    items.forEach(function(item) {
        array.push(item);
    });
}
let a = [];
push(a, 1, 2, 3);
  • 7、函数重载

七、类

在面向对象语言中,类是一种面向对象计算机编程语言的构造,是创建对象的蓝图,描述了所创建的对象共同的属性和方法。面向对象的三大特性:封装、继承、多态
类(Class):定义了一切事物的抽象特点
对象(Object):类的实例
在 TypeScript 中,我们可以通过Class关键字来定义一个类:

  • 1、类的属性与方法
class Greeter {
  // 静态属性,不需要实例化也能直接调用
  static cname: string = "Greeter";
  // 成员属性
  greeting: string;
  // 构造函数 - 执行初始化操作
  constructor(message: string) {
    this.greeting = message;
  }
  // 静态方法
  static getClassName() {
    return "Class name is Greeter";
  }
  // 成员方法
  greet() {
    return "Hello, " + this.greeting;
  }
}

let greeter = new Greeter("world");
  • 2、访问控制符

public: 修饰的属性或方法是共有的,可以在任何地方被访问
private:修饰的属性和方法是私有的,只能被其定义所在的类访问
protected:修饰的属性或方法是受保护的,可以被其自身以及子类和父类访问

  • 3、访问器
    可以通过 gettersetter 方法来实现数据的封装和有效性校验,防止出现异常数据。
let passcode = "Hello TypeScript";

class Employee {
  private _fullName: string;

  get fullName(): string {
    return this._fullName;
  }

  set fullName(newName: string) {
    if (passcode && passcode == "Hello TypeScript") {
      this._fullName = newName;
    } else {
      console.log("Error: Unauthorized update of employee!");
    }
  }
}

let employee = new Employee();
employee.fullName = "Semlinker";
if (employee.fullName) {
  console.log(employee.fullName);
}
  • 4、继承
    通过 extends 关键字来实现继承:
class Animal {
  name: string;
  
  constructor(theName: string) {
    this.name = theName;
  }
  
  move(distanceInMeters: number = 0) {
    console.log(`${this.name} moved ${distanceInMeters}m.`);
  }
}

class Snake extends Animal {
  constructor(name: string) {
    super(name);
  }
  
  move(distanceInMeters = 5) {
    console.log("Slithering...");
    super.move(distanceInMeters);
  }
}

let sam = new Snake("Sammy the Python");
sam.move();

八、类和接口

interface Animal {
    name: string;
    eat(): void;
}
class Dog implements Animal {
    name: string;
    constructor(theName: string) {
        this.name = theName;
    }
    eat() {
        console.log(`${this.name} 吃狗粮。`)
    }
}
class Cat implements Animal {
    name: string;
    constructor(theName: string) {
        this.name = theName;
    }
    eat() {
        console.log(`${this.name} 吃猫粮。`)
    }
}
let dog: Animal;
dog = new Dog('狗狗');
dog.eat();

九、泛型

软件工程中,我们不仅要创建一致的定义良好的 API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

在像 C# 和 Java 这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

设计泛型的关键目的是在成员之间提供有意义的约束,这些成员可以是:类的实例成员、类的方法、函数参数和函数返回值。

泛型(Generics)是允许同一个函数接受不同类型参数的一种模板。相比于使用 any 类型,使用泛型来创建可复用的组件要更好,因为泛型会保留参数类型。

1、泛型接口
interface GenericIdentityFn<T> {
  (arg: T): T;
}
2、泛型函数
function identity <T, U>(value: T, message: U) : T {
  console.log(message);
  return value;
}
console.log(identity<Number, string>(68, "Semlinker"));
3、泛型类
class GenericNumber<T> {
  zeroValue: T;
  add: (x: T, y: T) => T;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
  return x + y;
};
4、泛型约束

假如我想打印出参数的 size 属性呢?如果完全不进行约束 TS 是会报错的:

function trace<T>(arg: T): T {
  console.log(arg.size); // Error: Property 'size doesn't exist on type 'T'
  return arg;
}

报错的原因在于 T 理论上是可以是任何类型的,不同于 any,你不管使用它的什么属性或者方法都会报错(除非这个属性和方法是所有集合共有的)。那么直观的想法是限定传给 trace函数的参数类型应该有size 类型,这样就不会报错了。如何去表达这个类型约束的点呢?实现这个需求的关键在于使用类型约束。 使用extends`关键字可以做到这一点。简单来说就是你定义一个类型,然后让 T 实现这个接口即可。

interface Sizeable {
  size: number;
}
function trace<T extends Sizeable>(arg: T): T {
  console.log(arg.size);
  return arg;
}

总体而言,TypeScript和Java很像很像

你可能感兴趣的:(Javascript,typescript,javascript,前端)