TypeScript 基础教程

2020-11-14 16:05:38 浏览数 (1)

请查看 附件,ppt 以及示例代码。title 处 #数字 表示对应示例代码片段。

为什么学习TS


  • 因为大家都在用,React、Vue、Angular、Antd、Element-UI、Mobx、Redux…
  • 因为大家都在学,既是一个前端的趋势也是提升扩展个人技术的不错方法。

为什么需要使用TS


通过引入强类型系统,补充JS的短板。原生JS类型的灵活性导致在实际环境中可能会出现各种不确定的bug。通过使用TS,我们可以在开发阶段既预测这些可能由类型转换导致的错误,从而提前规避bug,开发出更健全的程序。

TypeScript 的安装与基础使用


安装:

npm i typescript -g

使用:

  • tsc { ptah }/{ fileName },可以直接将 .ts 文件 编译为 .js文件
  • tsc -- init , ⽣成项⽬配置:tsconfig.json,通过配置文件可以设置 .ts 文件

TypeScript 的基本类型


boolean:

同 js 布尔值类型,true / false。

string:

同 js 字符串类型,使⽤单引号、双引号、模版字符串。

number:

数字类型,⼆进制、⼋进制、⼗进制、⼗六进制。

null、undefined:

null,undefined :同js值类型,默认是所有类型的⼦类型所以,可以给任意类型的变量赋值nullundefined

any:

定义:任意值类型,可以赋值任意值类型,注意这里与 null,undefined有区别,null,undefined 是所有类型的子类型,表明它是所有类型的子集,而 any 类型则是:“所有类型都是 any 类型的子集”。

代码语言:txt复制
let baz: string = "baz";
let bar: number = 1;
let qux: boolean = false;
let foo: any = 1;
let norf: null = null;
qux = null;
qux = undefined;
foo = "foo"

void:

定义:无返回值的值类型,可以理解为 undefined 类型的子类型。作为一个类型,它也可以当作函数参数类型限定

代码语言:txt复制
button.onclick = () => void doSomething();

function doSomething(callback: () => void) {
  let foo = callback();
}

never:

定义:表示永远不存在的值类型,比如:程序运行报错,程序陷入了无线循环。

代码语言:txt复制
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
  throw new Error(message);
}

// 推断的返回值类型为never
function fail() {
  return error("Something failed");
}

// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
  while (true) {
  }
}

Symbol 类型 当前并无支持

type 类型别名


定义:给⼀个类型起⼀个新的名字,使⽤ type 作为声明关键字。常用于复合类型数据变量的类型声明。 对象类型约定使用大写字母开头type 声明的类型,里面包含的属性必须刚好全部满足,不能多也不能少,否则编译将报错,可选属性除外。

代码语言:txt复制
type Name = string;
const myName: Name = "foo";

type Age = number;
const myAge: Age = 18;

// 声明复杂类型
// 类型声明里的属性必须存在,可选属性声明前使用: "?"
type User = {
  name: string;
  sex: string;
  age: number;
  adult: boolean;
  isProgramer?: boolean; // isProgramer是可选属性
};

let foo: User = {
  name: 'foo',
  sex: "man",
  age: 18,
  adult: true,
  isProgramer: true
};
/*
// Error 
let bar: User = {
  weight: 100
}
*/

interface 接口


定义: 对⾏为或是事物的抽象,进⾏描述。具体⾏为由类(function/class)去实现 (implement)。

举例:招募一个鸭子合唱团,招募要求是会:呱呱呱的叫声。这时候如果有一只公鸡,并且它的叫声是 “呱呱呱” 那么它便可以被招募,可以成为鸭子合唱团中的一员,或者说可以被当作鸭子。所以 interface 只是对某一类事物进行描述,如果一个具体事物拥有这样的属性, 那么它就是这一类型。 同类型别名 type 属性声明,可以使用 ?声明可选属性。

代码语言:txt复制
// 定义接口
interface Person {
  sex: string;
  age?: number;
}
// 数据直接赋值
let bar: Person = {
  sex: "man",
  age: 18,
}
// 对接口进行实现
class Chinese implements Person{
  name: string;
}
// 构造调用与赋值
const wilde = new Chinese();
wilde.name = "mouguiding";

注意:类型别名 type 与接口interface 都可以声明复合类型类型的变量, 他们同样可以使用 readonly 来声明只读类型的属性, 使用 ? 来声明可选属性,但是他们存在一定区别。

type 与 interface 的异同

  • 都可以描述一个对象或者函数
  • 都允许扩展
  • type 可以声明基础类型别名,联合类型,元组等。 interface不可以
  • interface 可以声明合并。
代码语言:txt复制
{
  // 描述一个对象或是函数
  {
    interface User {
      name: string
      age: number
    }
    interface SetUser {
      (name: string, age: number): void;
    }
  }
  {
    type User = {
      name: string
      age: number
    };
    type SetUser = (name: string, age: number)=> void;
  }

  // 扩展
  {
    interface Name { 
      name: string; 
    }
    interface User extends Name { 
      age: number; 
    }
  }
  {
    type Name = { 
      name: string; 
    }
    type User = Name & { age: number  };    
  }
  {
    type Name = { 
      name: string; 
    }
    interface User extends Name { 
      age: number;
    }
  }
  {
    interface Name { 
      name: string; 
    }
    type User = Name & { 
      age: number;
    }
  }
  // 不同点
  // type可以 interface 不行的
  {
    // 基本类型别名
    type Name = string
    // 联合类型
    interface Dog {
        wang();
    }
    interface Cat {
        miao();
    }
    type Pet = Dog | Cat
    // 具体定义数组每个位置的类型
    type PetList = [Dog, Pet]
    // 当你想获取一个变量的类型时,使用 typeof
    let div = document.createElement('div');
    type B = typeof div
  } 
  // interface 可以  type 不可以的, 声明属性合并
  {
    interface Person {
      name: string
      age: number
    }
    interface Person {
      sex: string
    }
    interface Programer extends Person{
      skill: string;
    }
  }

}

Typescript 中数组的类型声明


类型声明使用 Type:[] 或者 Array<Type>,尖括号<> 用于类型约束

代码语言:txt复制
// 声明元素类型为字符串的数组
let foo: string[] = [ “foo”, “bar”, “baz” ]

// 声明元素类型为字符串的数组
let bar: Array<string> = [ “foo”, “bar”, “baz” ]
// bar.push(5) // error

// 声明元素类型为字符串或者数字的数组
let baz: Array<string|number> = [ “foo”, 100 ]
baz.push(10);

Typescript 中对象的类型声明


代码语言:txt复制
// 使用 类型别名声明类型
type User = {
  name: string;
  sex: string;
  age: number;
  adult: boolean;
  isProgramer?: boolean;
};
let foo: User = {
  name: 'foo',
  sex: "man",
  age: 18,
  adult: true,
  isProgramer: true,
};

// 使用接口 interface 声明类型
interface Person {
  readonly name: string;
  sex?: string;
  age?: number;
}
let bar: Person = {
  name: 'bar',
  sex: "man",
  age: 18,
}

Typescript 中函数的类型声明


函数声明主要涉及到函数参数类型声明以及函数返回值类型限定。

代码语言:txt复制
let fun71: any;
fun71 = function(): void {
  console.log("I'm fun71");
}
function fun72(): any {
  return "any";
};

let fun73: Function;
fun73 = function(): void{
  console.log("I'm fun73");
};

let fun74: (str: string) => string;
fun74 = function(name) {
  return `I'm ${name}`;
};

type Fun75 = (str: string) => string;
const fun75: Fun75 = function(name) {
  return `I'm ${name}`;
};

interface Fun76{
  (x: number, y: number): number;
}
const fun76: Fun76 = (x, y) => {
  return x   y;
}

interface Fun77{
  (x: number, y?: number): number;
}
const fun77: Fun77 = (x, y) => {
  if (y) return x   y;
  return x; 
}

函数重载

函数重载允许用相同的名字与不同的参数来创造多个函数

  1. 先提供没有实现的函数定义列表
  2. 必须提供所有函数组合的实现
代码语言:txt复制
function sum(x: number, y: number): number;
function sum(x: number, y: number, z: number): number

function sum(x: number, y: number, z?: number): number {
	if (typeof z === 'undefined') {
		return x   y;
	} else {
		return x   y   z;
	}
}
let n = sum(1, 2, 3);
console.log(n);
n = sum(1, 2);
console.log(n);

Typescript 高级类型


union 联合类型:

定义:该类型的取值可以是多种类型的⼀种, 使用竖线对多种类型进行联合。每个类型可以是单一类型或复合类型

代码语言:txt复制
type RTX = number|string|null;
let foo: RTX = "bar";
foo = 123;
foo = null;
foo = undefined;

interface Dog {
  wang();
}
interface Cat {
  miao();
}
type Pet = Dog | Cat

Tuple 元组:

定义:数组合并了相同类型的对象,元组则是合并了不同类型的对象,并且指定位置。注意是指定位置,与数组声明不同的是,数字只是限定了类型,不限定长度与位置

代码语言:txt复制
interface Dog {
  wang();
}
interface Cat {
  miao();
}
type Pet = Dog | Cat
// 具体定义数组每个位置的类型, 值类型位置不能变换。
type PetList = [Dog, Pet, Cat];
let dog: Dog = {
  wang: () => {}
}
let cat: Cat = {
  miao: () => {}
}
let petlist: PetList = [dog, dog, cat]

enum 枚举:

定义: 类型⽤于取值被限定在⼀定范围内的场景 ,⽐如⼀周只能有七天,颜⾊限定为红绿蓝等,值为序号,可⾃定义值。重点:值为序号,相当于数组的下标,而不是本身。

代码语言:txt复制
// 它的值是数字序号,从 0 开始
// 代码可读性强
// 可能会常用于下拉框等应用
enum DaysOfTheWeek {
	SUN = 100, MON, TUE, WED, THU, FRI, SAT
}
let day: DaysOfTheWeek;
	day = DaysOfTheWeek.MON;
if (101 === day) {
	console.log("Got to go to work");
} else {
	console.log("Don't work");
}

字面量类型:

定义:字面量类型使用竖线直接分割值(PS:联合类型是使用竖线联合类型,这里是值),此变量的值只能从分隔的值其中一个,使用 类型别名 type 搭配 |声明。

代码语言:txt复制
type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
    // do something
}
// handleEvent(document.getElementById('hello'), 'scroll');  // 没问题
// handleEvent(document.getElementById('world'), 'dbclick'); // 报错,event 不能为 'dbclick'

Generics 泛型:

定义:是指在定义函数、接⼝或类的时候,不预先指定具体的类型,⽽在使⽤的时候再指定类型的⼀种特性。泛型不是 any

代码语言:txt复制
// 实现一个方法,输入两个参数,第一个是数字 N,
// 第二个是一个简单类型数据,返回重复 N 次的指定类型数组
type CreateArrayType<T> = (x:number, y:T) => T[];
const createArray2:CreateArrayType<number> = (x, y) => {
  let result = [];
  for(let i=0; i<x; i  ){
    result[i] = y;
  }
  return result;
}
createArray2(2, 2);

其他部分


类型约束:

类型约束,常见的为使用<>进行限定。

如数组声明中:

代码语言:txt复制
let arr53: Array<string|number|boolean> = [true, 100, "bar"];

其次如当我们需要返回一个变量的长度时,首先这个变量需要一个长度的属性那么,声明变量类型时它应该拥有长度属性:

代码语言:txt复制
// 声明 LengthType 类型,必须包含 length 属性
interface LengthType {
  length: number;
}

// T 继承自 LengthType 类型,也就表明它必须具有 length 属性
function get<T extends LengthType>(arg: T): number {
  return arg.length;
}

特别是在使用泛型时,因为类型的不确定性导致程序可能会运行报错,善用类型约束可以提前处理这些问题。

类型断言:

可以理解为类型强制转换,就是把一个变量指定为另一个类型。

代码语言:txt复制
let foo: any;
let bar = <string>foo; // 现在 bar 的类型是 'string'

interface Foo {
  bar: number;
  bas: string;
}
const foo = {} as Foo;

// 双重类型断言
function handler(event: Event) {
  const element = (event as any) as HTMLElement; 
}

类型推论:

定义:TypeScript 会通过变量或返回值等赋值时推导出这个值的类型,如果在随后的代码中又进行了不同类型的值赋值,那么编译会报错:

代码语言:txt复制
let foo = 'hello,world';
foo = 9999;
Type '9999' is not assignable to type 'string'.

如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成 any 类型而完全不被类型检查

代码语言:txt复制
let foo;
foo = 'bar';
foo = 18;     //ok

特别对于联合类型时,类型推论会限制到只能访问联合类型中类型的共有属性。否则将报错。

代码语言:txt复制
//正确,因为num都有toString方法
function test(num: string | number) {
  return obj .toString()
}
let num = 'server';
console.log(test(num))

//编译错误,number类型的num 不存在length属性
function test(num: string | number) {
  return num.length;
}
let num = 'server';
console.log(test(num))

0 人点赞