TypeScript学习

1.TypeScript介绍

TypeScript是一种由微软开发的开源、跨平台的编程语言。它是JavaScript的超集,最终会被编译为JavaScript代码。2012年10月,微软发布了首个公开版本的TypeScript,2013年6月19日,在经历了一个预览版之后微软正式发布了正式版TypeScript。TypeScript的作者是安德斯·海尔斯伯格,C#的首席架构师。它是开源和跨平台的编程语言。是为大型应用的开发而设计,并且可以编译为JavaScript,是 JavaScript 的一个超集,主要提供了类型系统和对 ES6+ 的支持

 TypeScript 可以编译出纯净、 简洁的 JavaScript 代码,并且可以运行在任何浏览器上、Node.js 环境中和任何支持 ECMAScript 3(或更高版本)的JavaScript 引擎中,类型系统允许 JavaScript 开发者在开发 JavaScript 应用程序时使用高效的开发工具和常用操作比如静态检查和代码重构。

2.TypeScript安装 

2.1 全局安装 

npm install -g typescript

2.2 检查是否安装成功 ,查看版本

tsc -V 

3.TypeScript代码编译

新建 typescript/hello.ts文件,使用VSCode打开

编写ts代码 

console.log('hello TypeScript')

3.1手动编译 

命令行输入 

tsc helloworld.ts

输出结果为一个hello.js文件 ,这个就是将ts代码编译后的js代码

然后在命令行输入 

node hello.js

控制台输出 

hello TypeScript

手动编译就是当我们每次写完代码,都需要重新tsc hello.ts一下才能编译成js代码 ,比较麻烦

3.2自动编译

3.2.1生成tsconfig.json文件 

tsc --init

3.2.2 修改tsconfig.json配置

"outDir": "./js",
"strict": false

3.2.3 启动监视任务

终端 -> 运行任务 -> 监视tsconfig.json

4.TypeScript基础类型 

TypeScript 支持与 JavaScript 几乎相同的数据类型,此外新增一些类型方便(比如枚举)我们使用。 

4.1 字符串类型

let str: string = 'test'

4.2 数字类型

let num: number = 12

4.3 null类型 

let n: null = null

4.4 undefined类型 

let u: undefined = undefined

4.5 布尔类型 

let b:boolean = true

4.6 any类型 (少用)

let a: any = '我是任意类型的值'
a = 12
a = true
a = null
a = undefined
a = () => {}

let str1: string = 'wft'
str1 = a //不报错,any类型就相当于关闭了我们ts类型检查,所以尽量不使用

4.7 unknown类型 

//  未知类型
let unk: unknown = '12'

let str2: string = 'www'
// str2 = unk //报错,如果有未知类型,我们使用unknow来代替any

4.8 联合类型 

let unio: string | number | boolean = true
unio = '121'
unio = 10

4.9 数组类型 

let arr1: number[] = [1,2,3]
let arr2: Array = ['1', '2', '3']
let arr3: any[] = [1, '2', false, null, undefined]

4.10 元组Tuple类型 

数组长度固定 

let arr4:[string, number] = ['1', 2] // 正确
// arr4 = ['1',2, 3]  //报错
// arr4 = [2, '1'] // 报错

4.11 枚举类型 

// 枚举数值默认从0开始依次递增
// 根据特定的名称得到对应的枚举数值
enum Flag1 {
  name = 'wft',
  age = 18
}
enum Flag2 {
  name,
  age = 18,
  height
}
enum Flag3 {
  name,
  age,
  height
}
let flag1: Flag1 = Flag1.name
let flag2: Flag2 = Flag2.height
let flag3: Flag3 = Flag3.height;
console.log(flag1, flag2, flag3); // wft 19 2

4.12 void类型 

void类型一般用于函数没有返回值,即默认值返回值为undefined 

(function fn(): void {
  console.log('我没有返回值~~');
})()

4.13 never类型 

这个也是表示没有任何的返回值,他和void的区别就是,void可以返回,只不过是没有值(undefined),但是never是返回undefined都不行,压根就不能有返回,一般用于抛出错误 

function err(): never {
  throw new Error('抛出错误')
}

4.14 类型断言 

类型断言就是可以手动指定一个值的类型。通过类型断言这种方式就好比告诉编译器:“相信我,我知道自己在干什么”, 它没有运行时的影响,就代码该怎么执行怎么执行,只是在编译阶段起作用,能够编译通过。两种语法:1.尖括号语法  2.as关键字

// 类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。
// 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 
// 它没有运行时的影响,只是在编译阶段起作用。 
// TypeScript 会假设你,程序员,已经进行了必须的检查。
// 方式一: <>值
// 方式二: as 关键字
function getLength(x: number | string): number {
  if ((x).length) {
    return (x as string).length
  } else {
    return x.toString().length
  }
}
console.log(getLength('abcd'), getLength(1234), '---->>') // 4 4

4.15 类型推断 

TS会在没有明确的指定类型的时候推测出一个类型

有下面2种情况: 1. 定义变量时赋值了, 推断为对应的类型. 2. 定义变量时没有赋值, 推断为any类型 

// 定义变量时赋值了,推断为对应的类型
let w = 110  // number类型
// w = 'hahha' // 报错

// 定义变量时没赋值,推断为any
let wn; //any类型
wn = 12
wn = '1212'

5.TypeScript函数 

和 JavaScript 一样,TypeScript 函数可以创建有名字的函数和匿名函数。你可以随意选择适合应用程序的方式,不论是定义一系列 API 函数还是只使用一次的函数。

TypeScript 为 JavaScript 函数添加了额外的功能,让我们可以更容易地使用 

5.1 函数声明 

function add (a: number, b: number): number {
  return a + b
}
add(1,2)

5.2 函数表达式 

const add = function(a: number, b: number): number {
  return a + b
}
add(1,2)

5.3 必选参数 

function getInfo(name: string, age: number) {
  return `${name}今年${age}岁了`
}

getInfo('小王', 12)

5.3 可选参数 

function getInfo(name: string, age?: number) {
  return age ? `${name}----${age}` : `---${name}---`
}

getInfo('小王', 12)
getInfo('我是小王')

5.4  默认参数

注意:可选参数不能设置默认值 

function getInfo(name: string = '小王', age: number = 20) {
  return `${name}今年${age}岁了`
}

getInfo('小王', 12)
getInfo()

5.5 剩余参数 

function myInfo(name: string, ...args: string[]) {
  console.log(name, args)
}
myInfo('小王', '1', '2', '3')

5.6 函数重载

函数重载指的是形参不同的多个同名函数 

5.6.1 例1 

function info(name: string): string;
function info(name: string, age: number): string

//重载函数签名:就是把声明中出现的参数都写出来,如果可选,就使用可选参数,一个变量名可以使用多种类型用组合类型
function info(name: string, age?: number): string {
  if(age) {
    return `${name}今年${age}岁了`
  } else {
    return `我叫${name}`
  }
}
console.log(info("zhangsan"));
console.log(info("lisi", 20));
// console.log(info(123));// error

5.6.2 例2 

function add (x: string, y: string): string
function add (x: number, y: number): number

// 定义函数实现
function add(x: string | number, y: string | number): string | number {
  // 在实现上我们要注意严格判断两个参数的类型是否相等,而不能简单的写一个 x + y
  if (typeof x === 'string' && typeof y === 'string') {
    return x + y
  } else if (typeof x === 'number' && typeof y === 'number') {
    return x + y
  }
}
console.log(add(1, 2))
console.log(add('a', 'b'))
// console.log(add(1, 'a')) // error

6.接口 

json2ts 接口 

TypeScript 的核心原则之一是对值所具有的结构进行类型检查。我们使用接口(Interface)来定义对象的类型。接口是对象的状态(属性)和行为(方法)的抽象(描述) 

接口可以在定义对象(或者类)的时候去限制对象(或者类)的结构

接口中所有的属性都不能有实际的值

接口只定义对象的结构,而不考虑实际值

接口中所有的方法都是抽象方法 

6.1 属性类型接口 

 6.1.1 必选属性

interface Person {
  id: string,
  name: string,
  age: number
}

const IPerson: Person = {
  id: '001',
  name: 'wft',
  age: 18
}

6.1.2 可选属性 

interface Person {
  id: string,
  name: string,
  age: number,
  sex?: string
}

const IPerson: Person = {
  id: '001',
  name: 'wft',
  age: 18,
  // sex: '男' // 可以没有
}

6.1.3 只读属性 

interface Person {
  readonly id: string,
  name: string,
  age: number
}

const IPerson: Person = {
  id: '001',
  name: 'wft',
  age: 18
}

// IPerson.id = '121212'  // 不可修改

6.1.4 对象属性 

interface Info {
  height: string,
}

interface Person {
  id: string,
  name: string,
  age: number,
  info: Info // 对象
}

const IPerson: Person = {
  id: '001',
  name: 'wft',
  age: 18,
  info: {
    height: '1.88'
  }
}

6.1.5 任意key 

interface Person {
  id: string, // id是必须有的属性
  [PropName: string]: any // 其他的随意加什么
}

const IPerson: Person = {
  id: '001',
  name: 'wft',
  age: 18
}

6.2 函数类接口 

接口可以描述函数类型(即参数的类型与返回的类型) 

interface Reversal {
  (str1: string, str2: string): string
}

const strReverse: Reversal = (str1: string, str2: string): string {
  return (str1 + str2).split('').reverse().join('')
}

console.log(strReverse('123', '456'));

6.3 类类型接口 

interface Animal {
  name: string,
  eat(food: string): void
}

class Cat implements Animal {
  name: string

  constructor(name: string) {
    this.name = name
  }

  eat(food: string): void {
    console.log(`${this.name}吃${food}`);
  }
}

let cat = new Cat('猫')

cat.eat('鱼')

一个类实现多个接口 :

interface Animal1 {
  name: string,
  eat(food: string): void
}
interface Animal2 {
  age: number,
  fn(str: string): void
}

class Cat implements Animal1, Animal2 {
  name: string
  age: number

  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }

  eat(food: string): void {
    console.log(`${this.name}吃${food}`);
  }

  fn(): void {
    console.log(`${this.name}今年${this.age}岁了`);
  }
}

let cat = new Cat('猫', 2)

cat.eat('鱼')
cat.fn()

6.4 接口继承 

接口和类一样,也可以相互继承,这让我们能够从一个接口里复制成员到另一个接口里,可以更灵活地将接口分割到可重用的模块里。 

// 动物接口
interface Animal {
  name: string,
  eat(food: string): void
}

// 飞行动物
interface Fly extends Animal {
  wing(): void 
}

class Eagle implements Fly {
  name: string

  constructor(name: string) {
    this.name = name
  }

  eat(food: string): void {
    console.log(`${this.name}吃${food}`);
  }
  
  wing(): void {
    console.log('老鹰捉小鸡');
  }
}

let fly = new Eagle('老鹰')

fly.eat('小鸡')
fly.wing()

7.类 

对象是由类创建出来的,通过new关键字 ,当我们new的时候,就自动执行class中的constructor方法,创建出一个对象,并改变了this指向,指向创建出的对象

7.1 类的基本使用 

class C {
  name: string  // 省略了前面的public(默认)关键字

  constructor(name:string) {
    this.name = name
  }

  getName(): void {
    console.log(`我叫${this.name}`);
  }
}

let c = new C('wft')
c.getName()

7.2 类的继承 

class C {
  name: string  // 省略了前面的public(默认)关键字

  constructor(name:string) {
    this.name = name
  }

  getName():void {
    console.log(`我叫${this.name}`);
  }
}

class D extends C {
  age: number
  
  // 类的继承一旦使用了constructor就要使用super方法调用父类的构造方法
  constructor(name: string, age: number) {
    super(name)
    this.age = age
  }

  getInfo(): void {
    super.getName() // 调用父类的方法
    console.log(`${this.name}今年${this.age}了`);
  }
}

let d = new D('wft', 18)
d.getInfo()
d.getName()

7.3 属性修饰符 

class AttrTest {
  public name: string  // 公共类型的属性(默认),内部、外部、子类都可以访问到
  private age: number // 私有属性,只能在类内部访问
  protected sex: string // 在内部和子类可以访问、外部不能访问
  readonly id: string // 只读属性,只读属性必须在声明时或构造函数里被初始化
  constructor() {
    console.log('属性测试')
  }
}

7.4 静态属性 

上面讨论的都是类的实例成员,仅当类被实例化的时候才会被初始化的属性

静态属性不需要实例化,只需要static关键字,就可以通过类名直接访问

方法也是一样,这里就不再赘述

class AttrTest {
  static sta: string = '我是静态属性'
  constructor() {
    console.log('属性测试')
  }
}

console.log(AttrTest.sta);

7.5 抽象类 

抽象类就是提供给其他类继承的基类,不能直接被实例化

通过 abstract关键字定义抽象类和在抽象类内部定义抽象方法

abstract class C {
  name: string  // 省略了前面的public(默认)关键字

  constructor(name:string) {
    this.name = name
  }

  abstract fn(): void  //抽象方法不包含具体实现并且必须在派生类中实现

  getName():void {
    console.log(`我叫${this.name}`);
  }
}

class D extends C {
  age: number
  
  // 类的继承一旦使用了constructor就要使用super方法调用父类的构造方法
  constructor(name: string, age: number) {
    super(name)
    this.age = age
  }

  fn(): void { // 子类中必须实现抽象父类中的抽象方法
    console.log('父类中的抽象方法');
  }

  getInfo(): void {
    super.getName() // 调用父类的方法
    console.log(`${this.name}今年${this.age}了`);
  }
}

8.泛型 

泛型指的就是定义函数、接口或者类的时候我们不确定会传入什么类型的值,则不预先指定类型 ,而在使用的时候再指定具体类型的一种特性

8.1 函数泛型 

/**
 * 例1
 * @param value 不确定什么类型,我们传入什么类型就是什么类型
 * @returns 返回长度为1的包含value的数组
 */
function test(value: T): T[] {
  return [ value ]
}


/**
 * 例2
 * 创建一个包含count个value的数组
 * @param value 不确定什么类型,我们传入什么类型就是什么类型
 * @param count 数字类型
 * @returns 返回一个未知类型的数组
 */
function createArr(value: T, count: number): T[] {
  const arr:T[] = []
  for(let i = 0; i < count; i++) {
    arr.push(value)
  }
  return arr
}

console.log(createArr('push', 5))// [ 'push', 'push', 'push', 'push', 'push' ]

8.2 多个泛型参数的函数 

/**
 * 例3
 * 多个泛型参数的函数
 * @param value1 未知类型
 * @param value2 未知类型
 * @returns 返回长度为2的不确定类型的元组
 */
function test(value1: K, value2: V): [K, V] {
  return [value1, value2]
}

console.log(test(() => 1, 1)); //[ [Function], 1 ]

8.3 泛型接口 

interface IFn {
  (value: T): T
}

const fn: IFn = (value: string) => value

8.4 泛型类 

class TTest {
  name: T
  age: T
  fn: (a: T, b:T) => T

  constructor(name: T, age: T) {
    this.name = name
    this.age = age
  }
}
// 我们在实例化的时候传入泛型的类型,就是为泛型指定一个类型
let o = new TTest('wft', '12')
o.fn = function(a, b) {
  return a + b
}

学习参考:

学习TypeScript4这一篇就够了

Vue3 + TS快速上手

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