TS基础知识

基础

基础操作

  • 编译代码tsc helloworld.ts,在html中使用ts,要先转成js
  • vscode可以自动编译ts成js 参考:https://24kcs.github.io/vue3_study/chapter1/03_HelloWorld.html#%E6%89%8B%E5%8A%A8%E7

接口

  • 是一种约束,要求一定要有指定的东西,下面的接口Person,要求一定要有firstName和lastName。在greeter函数中要求了person一定要有Person接口指定的东西,不然执行就会拨错
interface Person {
  firstName: string
  lastName: string
}

function greeter (person: Person) {
  return 'Hello, ' + person.firstName + ' ' + person.lastName
}

let user = {
  firstName: 'Yee',
  lastName: 'Huang'
}

console.log(greeter(user))

  • 定义了一个user类,constructor和python中的__init__类似,在user实例化的时候回初始化firstName lastName fullName
class User {
  fullName: string
  firstName: string
  lastName: string

  constructor (firstName: string, lastName: string) {
    this.firstName = firstName
    this.lastName = lastName
    this.fullName = firstName + ' ' + lastName
  }
}

interface Person {
  firstName: string
  lastName: string
}

function greeter (person: Person) {
  return 'Hello, ' + person.firstName + ' ' + person.lastName
}

let user = new User('Yee', 'Huang')

console.log(greeter(user))

webpack打包

  • 依赖的版本很重要。版本不一样很可能启动有问题。
npm install -D typescript@4.0.5  webpack@4.41.5 webpack-cli@3.3.10 webpack-dev-server@3.10.2  ts-loader@8.0.11  html-webpack-plugin@4.5.0 cross-env@7.0.2 clean-webpack-plugin@3.0.0
  • tsc --init 初始化package.json
{
  "name": "dabao",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.config.js",
    "build": "cross-env NODE_ENV=production webpack --config build/webpack.config.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "clean-webpack-plugin": "^3.0.0",
    "cross-env": "^7.0.2",
    "html-webpack-plugin": "^4.5.0",
    "ts-loader": "^8.0.11",
    "typescript": "^4.0.5",
    "webpack": "^4.41.5",
    "webpack-cli": "^3.3.10",
    "webpack-dev-server": "^3.10.2"
  }
}

  • build/webpack.config.js 打包的配置文件
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

const isProd = process.env.NODE_ENV === 'production' // 是否生产环境

function resolve (dir) {
  return path.resolve(__dirname, '..', dir)
}

module.exports = {
  mode: isProd ? 'production' : 'development',
  entry: {
    app: './src/main.ts'
  },

  output: {
    path: resolve('dist'),
    filename: '[name].[contenthash:8].js'
  },

  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        include: [resolve('src')]
      }
    ]
  },

  plugins: [
    new CleanWebpackPlugin({
    }),

    new HtmlWebpackPlugin({
      template: './public/index.html'
    })
  ],

  resolve: {
    extensions: ['.ts', '.tsx', '.js']
  },

  devtool: isProd ? 'cheap-module-source-map' : 'cheap-module-eval-source-map',

  devServer: {
    host: 'localhost', // 主机名
    stats: 'errors-only', // 打包日志输出输出错误信息
    port: 8081,
    open: true
  },
}
  • public/index.html 入口的html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>webpack & TS</title>
</head>
<body>
  
</body>
</html>
  • 入口JS: src/main.ts

document.write('Hello Webpack TS!')

  • 启动命令
# 运行
npm run dev 

# 打包成dist
npm run build 

常用语法

基础类型

ts中变量开始是什么类型就是什么类型,后期不能改的

boolean

true和false

# boolean
let isDone: boolean = false;
isDone = true;
// isDone = 2 // error

number

数字 ts中的所有数字都是浮点型

let a1: number = 10 // 十进制
let a2: number = 0b1010  // 二进制
let a3: number = 0o12 // 八进制
let a4: number = 0xa // 十六进制

string

字符串,单引号双引号都行

let name:string = 'tom'
name = 'jack'
// name = 12 // error
let age:number = 12
const info = `My name is ${name}, I am ${age} years old!`

undefinednull

是所有类型的子类型

let u: undefined = undefined
let n: null = null

数组

# 元素后加[]
let list1: number[] = [1, 2, 3]

# Array<元素类型>
let list2: Array<number> = [1, 2, 3]

元组Tuple

let t1: [string, number]
t1 = ['hello', 10] // OK
t1 = [10, 'hello'] // Error

console.log(t1[0].substring(1)) // OK
console.log(t1[1].substring(1)) // Error, 'number' 不存在 'substring' 方法

枚举enum

enum Color {
  Red,
  Green,
  Blue
}

# 枚举数值默认从0开始依次递增
# 根据特定的名称得到对应的枚举数值
let myColor: Color = Color.Green  # 0
console.log(myColor, Color.Red, Color.Blue)

# 可以手动指定元素的数值,随便改
enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green

# 可以根据值得到名字
enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2]

console.log(colorName)  // 'Green'

any

在不确定变量的类型时,不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any 类型

let notSure: any = 4
notSure = 'maybe a string'
notSure = false // 也可以是个 boolean

缺点就是不会有错误提示,比如一个number类型,用了split方法,他也是不会报错的,只有在真正执行的时候才会报错,如下

let arr: any[] = [100, 'hahah', true]
console.log(arr)
console.log(arr[0].split(''))

void

在函数申明是,在小括号后面使用void,代表该函数没有任何返回值

/* 表示没有任何类型, 一般用来说明函数的返回值不能是undefined和null之外的值 */
function fn(): void {
  console.log('fn()')
  // return undefined
  // return null
  // return 1 // error
}

# 可以申明void变量,但是没什么用
let unusable: void = undefined

object

表示非原始类型,除了number,string,boolean,其他的类型都可以

    function getObj(obj: object): object {
        console.log(obj)
        return{
            name: 'xxx',
            age: 18
        }
    }
    console.log(getObj({name: 'qqq', age: 99}))
    // console.log(getObj('123')) //报错的
    console.log(getObj(new String('123')))
    console.log(getObj(String))

联合类型

就是取值可以为多种类型的一种

function toString2(x: number | string) : string {
  return x.toString()
}

类型断言

告诉编辑器,我知道我自己是什么类型,也知道自己在干嘛

/* 
类型断言(Type Assertion): 可以用来手动指定一个值的类型
语法:
    方式一: <类型>值 <string>x
    方式二: 值 as 类型  x as string tsx中只能用这种方式
*/

/* 需求: 定义一个函数得到一个字符串或者数值数据的长度 */
function getLength(x: number | string) {
  if ((<string>x).length) {
    return (x as string).length
  } else {
    return x.toString().length
  }
}
console.log(getLength('abcd'), getLength(1234))

类型推断

TS会在没有明确的指定类型的时候推测出一个类型
有下面2种情况: 1. 定义变量时赋值了, 推断为对应的类型. 2. 定义变量时没有赋值, 推断为any类型

let txt = 100
console.log(txt) // txt 是number类型

let txt2  // 推断为any类型

接口

接口: 是对象的状态(属性)和行为(方法)的抽象(描述

定义

// 定义人的接口
interface IPerson {
  id: number
  name: string
  age: number
  sex: string
}

const person1: IPerson = {
  id: 1,
  name: 'tom',
  age: 20,
  sex: '男'
}

可选属性

在可选属性名字定义的后面加一个 ? 符号

interface IPerson {
  id: number
  name: string
  age: number
  sex?: string
}

只读属性

属性名前用 readonly 来指定只读属性。赋值后就不能修改,做为变量使用的话用 const,若做为属性则使用 readonly

interface IPerson {
  readonly id: number
  name: string
  age: number
  sex: string
}

函数类型

接口可以描述函数的类型

# 定义一个接口,作为某个函数的类型来使用
interface SearchFunc {
  (source: string, subString: string): boolean
}

# 定义了一个哈拿书,类型就是上面定义的接口
const mySearch: SearchFunc = function (source: string, sub: string): boolean {
  return source.search(sub) > -1
}

console.log(mySearch('abcd', 'bc'))

类类型

可以用接口来明确的强制一个类去符合某种契约

  • 接口和接口之间叫继承,用extends
  • 类和接口之间叫实现,用implements
interface Alarm {
  alert(): any;
}

interface Light {
  lightOn(): void;
  lightOff(): void;
}

class Car implements Alarm {
  alert() {
      console.log('Car alert');
  }
}

# 1. 一个类可以实现多个接口
class Car2 implements Alarm, Light {
  alert() {
    console.log('Car alert');
  }
  lightOn() {
    console.log('Car light on');
  }
  lightOff() {
    console.log('Car light off');
  }
}

# 2、 一个接口可以继承多个接口
interface LightableAlarm extends Alarm, Light {}

示例

类可以理解为模板,通过模板实例化对象,

  • 用claas来定义类
  • constructor 构造函数,对属性的值初始化,类似python的__init__
  • this类似python类中的self
(()=>{
    class Person {
        name: string
        age: number
        gender: string

        constructor (name:string = 'xxx', age: number=3, gender:string = 'girl') {
            this.name = name
            this.age = age
            this.gender =gender
        }
        
        // 定义实例方法
        sayHi(str: string){
            console.log(`wo shi ${this.name}, wo ${this.age} sui, shi ge ${this.gender}, `,str)
        }
    }

    const person = new Person('biubiubiu', 20, 'boy')
    person.sayHi('ouououo')

})()

继承

是类和类之间的关系

  • A类继承了B类。A叫子类,B叫父类
  • 子类—> 派生类
  • 父类—> 超类(父类)
  • 继承要用extends
class Animal {
    run (distance: number) {
      console.log(`Animal run ${distance}m`)
    }
  }
  
  class Dog extends Animal {
    cry () {
      console.log('wang! wang!')
    }
  }
  
  const dog = new Dog()
  dog.cry() 
  dog.run(100) // 可以调用从父中继承得到的方法
  • 子类中调用父类的构造函数和实例方法,必须要用super,这是规定
  • 子类中可以重写父类中的方法
class Animal {
  name: string
  
  constructor (name: string) {
    this.name = name
  }

  run (distance: number=0) {
    console.log(`${this.name} run ${distance}m`)
  }

}

class Snake extends Animal {
  constructor (name: string) {
    // 调用父类型构造方法
    super(name)
  }

  // 重写父类型的方法
  run (distance: number=5) {
    console.log('sliding...')
    super.run(distance)
  }
}

class Horse extends Animal {
  constructor (name: string) {
    // 调用父类型构造方法
    super(name)
  }

  // 重写父类型的方法
  run (distance: number=50) {
    console.log('dashing...')
    // 调用父类型的一般方法
    super.run(distance)
  }

  xxx () {
    console.log('xxx()')
  }
}

const snake = new Snake('sn')
snake.run()

const horse = new Horse('ho')
horse.run()

// 父类型引用指向子类型的实例 ==> 多态
const tom: Animal = new Horse('ho22')
tom.run()

/* 如果子类型没有扩展的方法, 可以让子类型引用指向父类型的实例 */
const tom3: Snake = new Animal('tom3')
tom3.run()
/* 如果子类型有扩展的方法, Horse中有xxx实例方法,所以不能让子类型引用指向父类型的实例 */
// const tom2: Horse = new Animal('tom2')
// tom2.run()

受保护的修饰符

  • public 公共的,默认都是public
  • private 私有的,外部无法访问,子类中也无法访问
  • protected,受保护的,类中和子类中都可以访问,外部无法访问。
/* 
访问修饰符: 用来描述类内部的属性/方法的可访问性
  public: 默认值, 公开的外部也可以访问
  private: 只能类内部可以访问
  protected: 类内部和子类可以访问
*/

class Animal {
  public name: string

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

  public run (distance: number=0) {
    console.log(`${this.name} run ${distance}m`)
  }
}

class Person extends Animal {
  private age: number = 18
  protected sex: string = '男'

  run (distance: number=5) {
    console.log('Person jumping...')
    super.run(distance)
  }
}

class Student extends Person {
  run (distance: number=6) {
    console.log('Student jumping...')

    console.log(this.sex) // 子类能看到父类中受保护的成员
    // console.log(this.age) //  子类看不到父类中私有的成员

    super.run(distance)
  }
}

console.log(new Person('abc').name) // 公开的可见
// console.log(new Person('abc').sex) // 受保护的不可见
// console.log(new Person('abc').age) //  私有的不可见

readonly

  • 对类中的属性成员进行修改,在外部不能修改。
  • 只有在构造函数中能修改
class Person {
  readonly name: string = 'abc'
  constructor(name: string) {
    this.name = name
  }
}

let john = new Person('John')
// john.name = 'peter' // error

存取器

ts中可以用getter和setter来设置类中的成员属性

class Person {
  firstName: string = 'A'
  lastName: string = 'B'
  get fullName () {
    return this.firstName + '-' + this.lastName
  }
  set fullName (value) {
    const names = value.split('-')
    this.firstName = names[0]
    this.lastName = names[1]
  }
}

const p = new Person()
console.log(p.fullName)

p.firstName = 'C'
p.lastName =  'D'
console.log(p.fullName)

p.fullName = 'E-F'
console.log(p.firstName, p.lastName)

静态成员

  • 和python中的staticmethod类似。都是存在与类上,不实例化就能使用的。
  • 这个属性是可以修改的。
  • 用static来设置
/* 
静态属性, 是类对象的属性
非静态属性, 是类的实例对象的属性
*/

class Person {
  name1: string = 'A'
  static name2: string = 'B'
}

console.log(Person.name2)
console.log(new Person().name1)

抽象类

  • 抽象类做为其它派生类的基类使用。
  • 它们不能被实例化。
/*
抽象类
  不能创建实例对象, 只有实现类才能创建实例
  可以包含未实现的抽象方法
*/

abstract class Animal {

  abstract cry ()

  run () {
    console.log('run()')
  }
}

class Dog extends Animal {
  cry () {
    console.log(' Dog cry()')
  }
}

const dog = new Dog()
dog.cry()
dog.run()

函数

示例

// 命名函数
function add(x, y) {
  return x + y
}

// 匿名函数
let myAdd = function(x, y) { 
  return x + y;
}

函数类型

function add(x: number, y: number): number {
  return x + y
}

let myAdd = function(x: number, y: number): number { 
  return x + y
}

## 完整地函数类型
let myAdd2: (x: number, y: number) => number = 
function(x: number, y: number): number {
  return x + y
}

参数

  • 可选参数,参数名旁使用 ? 实现
  • 默认参数
  • 剩余参数,在省略号( …)后面给定的名字,在函数内使用这个名字来操作,是数组
function buildName(firstName: string='A', lastName?: string): string {
  if (lastName) {
    return firstName + '-' + lastName
  } else {
    return firstName
  }
}

console.log(buildName('C', 'D'))
console.log(buildName('C'))
console.log(buildName())


function info(x: string, ...args: string[]) {
  console.log(x, args)
}
info('abc', 'c', 'b', 'a')

函数重载

  • 函数名相同, 而形参不同的多个函数
/* 
函数重载: 函数名相同, 而形参不同的多个函数
需求: 我们有一个add函数,它可以接收2个string类型的参数进行拼接,也可以接收2个number类型的参数进行相加 
*/

// 重载函数声明
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

泛型

  • 在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定具体类型的一种特性
  • 在函数后面加尖括号<>
  • 类似python中的多态

泛型定义示例

  • 添加了类型变量T。 T帮助我们捕获用户传入的类型(比如:number)。并且返回值的类型也是T。
  • 它可以适用于多个类型。用any的话,编辑器不会提示信息,用泛型的话,会提示。
  • 不一定要用T,用其他也行,只要数量和使用方式能对上
function identity<T>(arg: T): T {
    return arg;
}

# 1、传入所有的参数,包含类型参数
let output = identity<string>("myString");  
// type of output will be 'string'

# 2、利用了类型推论 -- 即编译器会根据传入的参数自动地帮助我们确定T的类型
let output = identity<string>("myString");  
// type of output will be 'string'

多个参数的泛型定义

function swap <K, V> (a: K, b: V): [K, V] {
  return [a, b]
}
const result = swap<string, number>('abc', 123)
console.log(result[0].length, result[1].toFixed())

泛型接口

在定义接口时, 为接口中的属性或方法定义泛型类型
在使用接口时, 再指定具体的泛型类型


# 定义一个泛型接口,有data,是一个T类型的数组;add,参数是T,没有返回值;getById,参数是number,返回值是T类型
interface IbaseCRUD <T> {
  data: T[]
  add: (t: T) => void
  getById: (id: number) => T
}

# 定义User类 
class User {
  id?: number; //id主键自增
  name: string; //姓名
  age: number; //年龄

  constructor (name, age) {
    this.name = name
    this.age = age
  }
}


# 定义CRUD类,用IbaseCRUD接口来实现,参数类型是User
class CRUD implements IbaseCRUD <User> {
  data: User[] = []
  
  add(user: User): void {
    user = {...user, id: Date.now()}
    this.data.push(user)
    console.log('保存user', user.id)
  }

  getById(id: number): User {
    return this.data.find(item => item.id===id)
  }
}


const userCRUD = new CRUD()
userCRUD.add(new User('tom', 12))
userCRUD.add(new User('tom2', 13))
console.log(userCRUD.data)

泛型类

在定义类时, 为类中的属性或方法定义泛型类型 在创建类的实例时, 再指定特定的泛型类型

# 定义了泛型的属性zeroValue和泛型的方法add
class GenericNumber<T> {
  zeroValue: T
  add: (x: T, y: T) => T
}

# 在实例化是制定泛型类型为number
let myGenericNumber = new GenericNumber<number>()
myGenericNumber.zeroValue = 0
myGenericNumber.add = function(x, y) {
  return x + y 
}

# 在实例化是制定泛型类型为string
let myGenericString = new GenericNumber<string>()
myGenericString.zeroValue = 'abc'
myGenericString.add = function(x, y) { 
  return x + y
}

console.log(myGenericString.add(myGenericString.zeroValue, 'test'))
console.log(myGenericNumber.add(myGenericNumber.zeroValue, 12))

泛型约束

直接对一个泛型参数取 length 属性, 会报错, 因为这个泛型根本就不知道它有这个属性。可以使用泛型约束来实现

// 没有泛型约束
function fn <T>(x: T): void {
  // console.log(x.length)  // error
}

// 约束了传入的值必须有length这个属性
interface Lengthwise {
  length: number;
}

// 指定泛型约束,继承lengthiwse这个接口
function fn2 <T extends Lengthwise>(x: T): void {
  console.log(x.length)
}

fn2('abc')
// fn2(123) // error  number没有length属性

声明文件

当使用第三方库时,我们需要引用它的声明文件,才能获得对应的代码补全、接口提示等功能。
声明语句: 如果需要ts对新的语法进行检查, 需要要加载了对应的类型说明代码
  declare var jQuery: (selector: string) => any;
声明文件: 把声明语句放到一个单独的文件(jQuery.d.ts)中, ts会自动解析到项目中所有声明文件
下载声明文件: npm install @types/jquery --save-dev

内置对象

所有js中的内置对象在ts中都可以直接使用

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值