ts从入门到跑路

目录

1.解析ts文件

2.数据类型

3.函数类型和断言

4.可选链-逻辑符号-字面量类型

5.类型缩小

6.函数参数和this绑定

7.重载和联合类型

8.类

9.接口

10.枚举与泛型

11.模块化开发


下文是根据王红元老师的学习笔记,并不作为ts学习

1.解析ts文件

1.运行ts文件
1.1方式一:安装ts-node
npm install ts-node -g
npm install tslib @types/node -g //ts-node需要依赖tslib和@types/node两个包
ts-node math.ts //运行ts文件

1.2方式二:webpack配置
1.2.1 包管理初始化
npm init
1.2.2 安装webpack和webpack-cli
npm install webpack webpack-cli -D
1.2.3 在package.json配置运行文件
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
}
1.2.4 配置webpack
const path = require('path')
module.exports = {
  entry: './src/main.ts',
  mode: 'development',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: "bundle.js"
  }
}
1.2.5下载ts解析
npm install ts-loader typescript -D
1.2.6初始化tsc(如果报错,下载方式一的两个包)
tsc --init
1.2.7配置webpack解析ts
resolve: {
    extensions: [".ts", '.js'] //使用.ts模块化引入时,可以识别ts文件(会覆盖原有的)
}
1.2.8(下边搭建本地服务器,上述操作已经可以运行ts文件)
1.2.8.1下载webpack本地服务器
npm install webpack-dev-server -D
1.2.8.2配置热更新
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "serve": "webpack serve"
}
1.2.8.3下载html模板
npm install html-webpack-plugin -D
1.2.8.4引入和使用模板
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
  entry: './src/main.ts',
  mode: 'development',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: "bundle.js"
  },
  resolve: {
    extensions: [".ts", '.js'] //使用.ts模块化引入时,可以识别ts文件
  },
  module: {
    rules: [
      {
        test: /\.ts$/,
        loader: 'ts-loader'
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({ //热更新时嵌入ts的文件
      template: './index.html'
    })
  ]
}

2.数据类型

// 1.数据类型
// 1.1数组类型
let strArr: string[] = ['abc', 'cbd']
strArr.push("123")
const myObj: object = {
  name: '小红',
  age: 18
}
// console.log(myObj.name) //报错不存在该值
// myObj.name = '小明' //报错不存在当前属性
// 1.1 当数值为null或者undefined时不要用类型推断,会被推断成any
let u: undefined = undefined
let n: null = null
// 1.2 symbol定义相同属性名称
let s1: symbol = Symbol('title')
let s2: symbol = Symbol('title')
const youObj: object = { //这边要用[],不加是当字符串处理的,取不到上边定义的是s1和s2
  [s1]: '我的家乡',
  [s2]: '我的村庄'
}
console.log('Symbol', youObj)
// 1.3any类型
let arrAny: any[] = [1.22, '小红', { name: '小红' }]
// 1.4unknow类型 用于描述类型不确定的变量
let k: unknown
function logSomedata() {
  if (Math.random() > 0.5) {
    return 'str'
  } else {
    return 123
  }
}
k = logSomedata()
console.log('unknown', k)
// 1.5void类型
function includeVoid(): void {
  console.log('返回值包含了void')
}
// 1.6返回值不包含void(默认)
function exculdeVoid() {
  console.log('返回值不包含了void')
}
let v1 = includeVoid()
let v2 = exculdeVoid()
console.log('明确了void', v1, '没有指定void', v2) //v1 和 v2 都是undefined
// 1.7never
// never 是其它类型(包括 null 和 undefined)的子类型,代表从不会出现的值。
// 这意味着声明为 never 类型的变量只能被 never 类型所赋值
function looping(): never { //1.7.1死循环
  while (true) {
    console.log('123')
  }
}
function looping2(): never { //1.7.2抛出一个错误 never 类型可以赋值给 never类型
  throw new Error('返回值是never')
}
function looping3(message: number | string) {
  switch (typeof message) {
    case 'string':
      console.log('foo')
      break
    case 'number':
      console.log('bar')
      break
    default:
      const check: never = message
  }
}
// --------菜鸟教程never
let x: never;
let y: number;
// 编译错误,数字类型不能转为 never 类型
// x = 123;
// 运行正确,never 类型可以赋值给 never类型
x = (() => { throw new Error('exception') })();
// 运行正确,never 类型可以赋值给 数字类型
y = (() => { throw new Error('exception') })();
// 返回值为 never 的函数可以是抛出异常的情况
function error(message: string): never {
  throw new Error(message);
}
// 返回值为 never 的函数可以是无法被执行到的终止点的情况
function loop(): never {
  while (true) { }
}
// -------菜鸟教程never
// 1.8tuple元祖每个元素都有自己特性的类型
const t1: [number, string, number] = [1, 'a', 3]
const t2: (number | string)[] = [1, 2, 3, 'b'] //如果写成[number|string]是只有一个元素(元素可以是number或者是string)

3.函数类型和断言

// 2.函数
let arr: (string | number)[] = ['abc', 'cbb', 123]
arr.forEach(item => { //item并没有指定类型,但是ts会  “上下文类型” 自动判断
  console.log(item)
})
// 2.1对象类型 + 可选类型
function objfunc(point: { x: number, y: number, z?: string }): number {
  if (point.z) {
    console.log('你传入了z属性' + point.z)
    //如果不加if并且传入了z,此时打印出来的就是undefined,因为可选类型就是类型和undefined的联合类型
  }
  return point.x ** point.y
}
console.log('2的3次方为', objfunc({ x: 2, y: 3 }))
// 2.2联合类型 + 缩小类型
function unionType(x: number | string) {
  if (typeof x === "number") {
    console.log("number", x * 2)
  } else {
    console.log("string", x.toUpperCase())
  }
}
unionType(2)
unionType('abc')
// 2.3类型别名
type obj1 = {
  x: number,
  y: number
}
type ali1 = number | string
function objfunc2(obj: obj1) {
  return obj.x * obj.y
}
console.log('类型别名', objfunc2({ x: 3, y: 4 }))
// 2.4断言(断言用于转化为具体或者不太具体的类型)+ 非空断言!.
// 断言只是处理了大多数的编译不会报错,只是程序员的个人判定,控制台仍然会报错
const myImg = document.querySelector('.img') as HTMLImageElement //如果没有断言,访问不了src属性
// myImg.src = './a.jpg'
const test = ("abc" as unknown) as number //abc值无法直接转为number的
console.log(test)
class Person {

}
class Student extends Person {
  studying() {
    console.log('学生在学习')
  }
}
function useStudying(p: Person) {
  (p as Student).studying() //断言用于缩小范围,不然是拿不到这个方法的(让编译以为p为Student)
}
const stu = new Student()
useStudying(stu)
function noEmpityAs(str?: string) {
  // console.log(str.toUpperCase()) //编译报错,会出现undefined现象
  console.log(str!.toUpperCase()) //这样做,只是编译不会报错,但是不传值时控制台会报错(让编译以为这是个必传的值)
}
noEmpityAs('abcde')

4.可选链-逻辑符号-字面量类型

// 3.可选链
type info = {
  name: string,
  age: number,
  sex: string,
  children?: {
    name?: string,
    age: number,
    sex: string,
  }
}
const ming: info = {
  name: '小明',
  age: 16,
  sex: '男',
}
console.log(ming?.children?.name) //一般只用于取值而不是赋值
// 4.!! + ?? 逻辑或||的本质是if语句的判断
let message = ""
console.log(!!message) //相当于Boolean,将类型转化为boolean类型
console.log(message ?? 123) //当??左侧为null或者undefined时返回右侧操作数,否则为左侧,这里打印""
// 5.字面量类型
// 5.1 字面量类型和联合类型一起使用才有意义
type direction = "right" | "left" | "top"
function move(d: direction) {
  switch (d) {
    case "right":
      console.log("right")
      break
    case "left":
      console.log("left")
      break
    case "top":
      console.log("top")
    default:
      console.log("error")
      break
  }
}
move("right")
// 5.2字面量推理
const config = {
  url: 'http://www.baidu.cn',
  method: "get"
}
function request(url: string, method: "get" | "post") {
  console.log(url, "发送了", method, "请求")
}
// ruquest(config.url, config.method) //报错:类型“string”的参数不能赋给类型“"get" | "post"”的参数
request(config.url, config.method as "get") //方法一:断言
const config1 = {
  url: 'http://www.baidu.cn',
  method: "get"
} as const //方法二:直接转化为字面量类型,而不是string类型
request(config1.url, config1.method)
type Method = "get" | "post" //方法三:编写一个字面量类型
function request1(url: string, method: Method) {
  console.log(url, "发送了", method, "请求")
}
request1(config.url, config.method as Method)

5.类型缩小

// 6.类型缩小
// 6.1typeof
type ID = number | string
function unionPd(id: ID) {
  if (typeof id === "string") {
    console.log('string')
  } else {
    console.log('number')
  }
}
// 6.2switch === == !== !=
type Direction = "right" | "left" | "top"
function Move(d: Direction) {
  switch (d) {
    case "right":
      console.log("right")
      break
    case "left":
      console.log("left")
      break
    case "top":
      console.log("top")
    default:
      console.log("error")
      break
  }
}
Move("right")
// 6.3instance of
function isDate(date: Date | string) {
  if (date instanceof Date) {
    console.log(date.toLocaleTimeString())
  } else {
    console.log(date.toString())
  }
}
// 6.4in 运算符,通常用于检测对象里的属性和方法
type Fish = { swim: () => void } //字面量类型
type dog = { run: () => void } //字面量类型
function sport(animal: Fish | dog) {
  if ('swim' in animal) {
    animal.swim()
  } else {
    animal.run()
  }
}
const fish: Fish = {
  swim() {
    console.log('鱼在游泳')
  }
}
sport(fish)

6.函数参数和this绑定

// 7.函数详解
// 7.1 void + ?(可选参数) + 默认参数=
function add(num1: number, num2?: number, num3: number = 6) {
  if (num2) {
    if (num3) {
      return num1 + num2 + num3
    } else {
      return num1 + num2
    }
  } else {
    return num1
  }
}
console.log(add(2, 6, 3))
// 7.2剩余参数
function mul(...num: number[]) {
  let total: number = 1
  for (const item of num) {
    total *= item
  }
  return total
}
console.log(mul(3, 4, 5))
// 7.3this指向
// 7.3.1this指向不明确
function sayHello() {
  // console.log('obj调用了', this.name) //报错this是拿不到的
}
const obj = {
  name: 'obj',
  sayHello
}
obj.sayHello()
// 7.3.2明确this指向
type thisType = {
  name: string
}
function sayHi(this: thisType, message: string) {
  console.log(this.name + message)
}
const obj2 = {
  name: 'obj2',
  sayHi
}
// 隐式绑定
obj2.sayHi('Hi Hi')
// 显示绑定
sayHi.call({ name: 'obj3' }, 'Hi Hi Hi')
sayHi.apply({ name: 'obj4' }, ['Hi Hi Hi Hi'])

7.重载和联合类型

// 7.4函数重载
// 7.4.1 参数类型混乱
// function sum(num1: number | string, num2: number | string): string | number {
//   return num1 + num2 //运算符“+”不能应用于类型“string | number”和“string | number”
// }
function sum(num1: string, num2: string): string
function sum(num1: number, num2: number): number
function sum(num1: any, num2: any): any {
  return num1 + num2
}
sum(1, 2)
sum('a', 'b')
// sum(true, false) 报错
// 7.4.2联合类型和重载(开发时尽量使用联合类型而不是重载)
function getLength(data: string | any[]) {
  return data.length
}
getLength('abc')
getLength([1, 2, 'ab'])
function getLength1(data: string): number
function getLength1(data: any[]): number
function getLength1(data: any): number {
  return data.length
}

8.类

// 8.类
class Person {
  name!: string //加上!就可以在constructor中不用明确赋值
  age: number
  constructor(name: string, age: number) {
    // this.name = name
    this.age = age
  }
  swim() {
    console.log(this.name, this.age, '---swim---') //如果没有在构造函数赋值这边就是undefined
  }
  run() {
    console.log(this.name, this.age, '---run---')
  }
}
// 8.1类的继承
class Student extends Person {
  sno: string
  constructor(name: string, age: number, sno: string) {
    super(name, age)
    this.sno = sno
  }
  swim() { //8.2重写父类的swim
    super.swim() //可以通过super调用父类方法
    console.log('son swimming' + this.sno)
  }
}
const p = new Person('xiaohong', 12)
const s = new Student('xiaolan', 13, '012')
p.run()
s.swim()

// 8.3多态
class Animal {
  action() {
    console.log('--animal--')
  }
}
class dog extends Animal {
  action(): void {
    console.log('--dog--')
  }
}
class fish extends Animal {
  action(): void {
    console.log('--fish--')
  }
}
function makeAction(animals: Animal[]) {
  animals.forEach(item => {
    item.action()
  })
}
makeAction([new dog(), new fish()])
// 8.4类的成员修饰符
class Figure {
  private x: number //private  -- 同一类可见(子类也拿不到h78)
  protected y: number //protected -- 同一类或子类
  constructor(x: number, y: number) {
    this.x = x
    this.y = y
  }
  getX() {
    return this.x
  }
}
class Rect extends Figure {
  readonly z: number //不允许修改,但是可以在构造函数里赋值
  readonly re?: Rect
  d: number
  constructor(x: number, y: number, z: number, d: number, re?: Rect) {
    super(x, y)
    this.z = z
    this.d = d
    this.re = re
  }
  getF() {
    // return this.x  //报错(super.x也是一样报错)
  }
  getY() {
    return this.y
  }
}
const f = new Figure(10, 20)
// f.x  报错--私有属性实例外部是拿不到的
console.log(f.getX()) //封装了getX方法来拿到内部的属性
// console.log(f.y) //报错外部是拿不到的
const r = new Rect(10, 20, 30, 20, new Rect(10, 20, 30, 40))
// r.z = 40  //只读属性不允许修改
if (r.re) {
  r.re.d = 10 //虽然re不可修改,但是re里的d是可修改的,理论类似于对象
}
// 8.5getter和setter + 静态成员
class tool {
  private _name: string //规范私有变量一般以下划线开头
  static tn: number = 10 //通过类名来访问修改,构造函数也不需要赋值(上下文是查找不到t的)
  constructor(name: string) {
    this._name = name
  }
  get name() {
    return this._name
  }
  set name(newName) {
    this._name = newName
  }
  getName() {
    return this._name
  }
  static sGetName() {
    // return this._name //报错,static方法访问不了内部属性
  }
}
const t = new tool('hairui')
t.name = "hairui view"
console.log(t.name, t.getName())
console.log(tool.tn)
console.log(tool.sGetName)
abstract class Shape {
  abstract calcWidth(): number
}
class Circle extends Shape {
  r: number
  constructor(r: number) {
    super()
    this.r = r
  }
  calcWidth(): number {
    return 3.14 * this.r ** 2
  }
}
const c = new Circle(2)
console.log(c.calcWidth())
// 8.6类的类型
class Demo {
  name: string
  constructor(name: string) {
    this.name = name
  }
}
const d = new Demo('xiaolan')
const d1: Demo = {
  name: 'xiaohong'
}
export { }

9.接口

// 9.接口
// 9.1定义接口
interface Point {
  name: string
  age?: number
  readonly friends: {
    name: string
  }
}
interface indexLanguage {
  [index: number]: string
}
const index: indexLanguage = {
  1: "java",
  2: "js",
  // 3: 12 //报错不能将string赋给number
}
interface calcWidth1 {
  (num1: number, num2: number): number
}
interface calcWidth2 {
  calc: (num1: number, num2: number) => number //可以两种声明方法只允许一个:(个人)
}
const c1: calcWidth1 = (num1, num2) => num1 + num2
const c2: calcWidth2 = {
  calc: (num1, num2) => num1 + num2
}
// 9.2接口的多继承
interface Animal {
  swimming: () => void
}
interface Person {
  name: string
  running: () => void
}
interface Student extends Animal, Person {
  sno: string
}
const s: Student = {
  name: 'code',
  sno: '1102',
  swimming() { },
  running() { }
}
// 9.3类继承接口--面向接口编程
class Teacher implements Animal, Person {
  name: string
  constructor(name: string) {
    this.name = name
  }
  swimming() {
    console.log('swimming' + this.name)
  }
  running() { }
}
function swim(swimmer: Animal) {
  swimmer.swimming()
}
const t = new Teacher('ter')
swim(t)
// 9.4交叉类型 不可能有属性既是string又是number,所以这个myType是never
type myType = string & number
// 以上是没有什么意义的,所以通常我们会对对象进行交叉
interface runIn {
  run: () => void
}
interface swimIn {
  swim: () => void
}
type allType1 = runIn & swimIn //使用该属性后两个方法都要实现
type allType2 = runIn | swimIn //使用该属性后两个方法实现一个即可
const allInter1: allType1 = {
  run() { },
  swim() { }
}
const allInter2: allType2 = {
  run() { },
  // swim() { }
}
// type和interface的区别
type one = {
  name: string
}
// type one = { //报错上边定义过one了
//   age: 12
// }
interface two {
  name: string
}
interface two {
  age: number
}
const twoS: two = {
  name: 'three',
  age: 12
}
// 9.5擦除操作和字面量赋值
interface Book {
  name: string,
  eating: () => void
}
const book: Book = {
  name: '小红',
  eating() {

  },
  // age: 12 //报错(类型推导会进行严格的类型限制)
}
const book2 = {
  name: '小红',
  eating() {

  },
  age: 12
}
const book1: Book = book2 //这样并没有报错(擦除操作)
console.log(book1) //并且该属性存在age,但是用book1.age编译会报错

// 因此定义非对象建议用type 比如Direction Alignment,一些Function
export { }

10.枚举与泛型

// 10.枚举
// 10.1增强阅读性
enum Direction {
  Left,
  Right,
  Top,
  Bottom
}
function turn(direction: Direction) {
  switch (direction) {
    case Direction.Left:
      console.log('左转')
      break
    case Direction.Right:
      console.log('右转')
      break
    case Direction.Top:
      console.log('上转')
      break
    case Direction.Bottom:
      console.log('下转')
      break
    default:
      break
  }
}
turn(Direction.Left) //阅读性较强
// 10.2枚举类型的值
enum Direction2 { //如果我们没有赋值,默认就是1234,如果第一个是100,那么依次递增101.102.103
  Left = 1,
  Right, //2
  Top = 3,
  Bottom = 'abc'
}
console.log(Direction2)//{1: 'Left', 2: 'Right', 3: 'Top', Left: 1, Right: 2, Top: 3, Bottom: 'abc'}
// (个人)只要是数字,就添加一个数组项的,可以通过Direction2[1]或Direction2["1"]获取
// 11.泛型
// 11.1泛型的基本用法
function foo<Type>(args: Type) {
  return args
}
foo('abc') //这里类型推导会判断是字面量类型,也是适用的
foo<number>(123) //类似于让用户决定输出的类型是啥
// 11.2传递多个参数
function foo1<T, E>(a1: T, a2: E) {
  if (typeof a1 === "string" && Array.isArray(a2)) { //下边的11.6方法更便捷
    return a1.length + a2.length
  }
}
console.log(foo1('abc', [1, 2, 3]))
// 11.3泛型接口 + 默认值
interface Person<T, N = number> { //泛型是没有额理性推导的,但是有默认值
  name: T,
  age: T[],
  handle: (value: T) => T
}
const p: Person<number> = {
  name: 105,
  age: [12, 13],
  handle: (value: number) => 12
}
// 11.4泛型类
class Animal<T> {
  name: T
  cno: T
  constructor(name: T, cno: T) {
    this.name = name
    this.cno = cno
  }
  eatting() {
    console.log(this.name + '的编号为' + this.cno)
  }
}
const a: Animal<string> = {
  name: '老虎',
  cno: "001",
  eatting() {
    console.log(this.name + '的编号为' + this.cno)
  }
}
const a1 = new Animal<string>('兔子', '002')
const a2 = new Animal('狮子', '003') //类型推导
a.eatting()
// 11.5泛型在数组的应用
const arr1: string[] = ['13', '12']
const arr2: Array<string> = ['a', 'b']
// 11.6泛型约束
interface ownLength {
  length: number //声明一个接口说明该对象是拥有length属性的
}
function getLength<T extends ownLength>(params: T) {
  return params.length
}
getLength([1, 2])
getLength('123')
// getLength(10) //编译报错,数字没有length属性
export { }

11.模块化开发

// 12.ts补充
// 12.1模块化开发
// 12.1 commonjs和namespace
import { sum } from './math'
import { space1 } from './math'
console.log(sum(10, 20))
console.log(space1.sub(20, 10))
const img = document.querySelector('.img') as HTMLImageElement //问:那么HTMLImageElement从哪里来喃?
// https://github.com/microsoft/TypeScript/tree/main/lib 答:ts自带的在.d.ts文件里做了声明
// console.log(img.src)
// 12.2外部文件声明
// 12.2.1方法一借助外部声明
// https://www.typescriptlang.org/dt/search/?search=
// https://www.typescriptlang.org/dt/search/?search=lodash(以lodash为例)
// 在上边的网址可以找到两条命令,一条是安装lodash,一条是lodash的声明文件
// npm i lodash npm i @types/lodash --save-dev
// import lodash from 'lodash'
// console.log(lodash.join([1, 2, 3]));
// 12.2.2方法二自己声明模块
import lodash from 'lodash' //默认是从node_modules找到hairui文件,但是找不到hairui
console.log(lodash.join([2, 6, 4])); //这样做的意义是避免lodash没有声明报错(相当于省略了npm i @types/lodash --save-dev)
// 但是这样写的话,用一个方法,就要写一个方法,很麻烦
declare module 'lodash' { //这边要加''
  export function join(arr: any[]) {
    return arr.join(' ')
  }
}
export function sum(num1: number, num2: number) {
  return num1 + num2
}
export namespace space1 {
  export function sub(num1: number, num2: number) { //函数和命名空间都要导出
    return num1 - num2
  }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值