TypeScript 学习笔记 环境安装-类型注解-语法细节-类-接口-泛型

这篇具有很好参考价值的文章主要介绍了TypeScript 学习笔记 环境安装-类型注解-语法细节-类-接口-泛型。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

TypeScript 学习笔记

概述

JavaScript的变量类型相当于是动态类型,可以跟随着赋值的改变而类型改变,函数的参数也没有设定类型,所以在定位错误以及安全性上不太够。

说明
1.TS不能被JS解析器直接执行,需要编译成JS执行
2.即使TS编译出错也可以编译成JS

1.TypeScript是什么?

TypeScript 是类型安全的JavaScript(拥有类型的JavaScript超集),JavaScript是弱类型, 很多错误只有在运行时才会被发现,而TypeScript提供了一套静态检测机制, 在编译时就发现错误

2.TypeScript的好处是什么?
1.支持强类型
2.类型注解:通过类型注解来增加编译时静态类型检查
3.增加了特性:泛型、接口、抽象类等

TypeScript 学习笔记 环境安装-类型注解-语法细节-类-接口-泛型,TypeScript/JavaScript,typescript,学习,笔记

TypeScript 开发环境搭建

安装TS解析器 :解析器使用nodejs写的 —> 先安装nodejs我node已经安装好啦,直接安装TypeScript

1.使用npm全局安装TypeScript

npm i -g typescript

2.检查是否安装成功

tsc --version

3.创建一个ts文件:后缀以ts结尾
使用tsc对ts文件进行编译,进入到该文件的命令行,使用tsc 文件名进行编译

tsc test.ts

TS运行效果查看
1.通过tsc编译TS代码到JS代码
2.在浏览器环境或者node环境下运行JS代码

简化版本

  • 通过webpack 配置本地的TS编译环境和开启一个本地服务,可以直接运行在浏览器上(ts-loader)
  • 通过ts-node库,为TS的运行提供执行环境
# 安装ts-node
npm install ts-node -g
# 按照ts-node依赖包tslib @types/node
npm install tslib @types/node - g
# node上运行js
node xxx.js
# node上运行ts
ts-node xxx.ts

类型注解

类型注解:主动告诉ts是什么类型
语法:变量名:数据类型
说明
1.冒号后面的数据类型被称为类型注解★
2.声明了类型后TS就会进行类型检测

类型推断

类型推断:声明一个变量时,如果有直接赋值,会根据赋值的类型推导出标变量的类型注解。

说明
1.声明变量如果不指定类型,也不赋值,则TS解析器会自动判断变量的类型为any
2.从右到左推断
3.let进行类型推导,推导出来是通用类型
const类型推导,推导出来是字面量类型

const height = 1.88 //1.88为heigth的类型,1.88是字面量类型
const height:1.88 //等价于

数据类型

  • JS数据类型: 7个原始类型 (string,number,boolean,undefined,null,bigint,symbol) + Array + Object
  • TS新增类型: any + unknow +void + never

总结
1.默认情况下 nullundefined 是所有类型的子类型,这两种类型可以赋值给任意类型的变量
4.never类型是任何类型的子类型,也可以赋值给任何类型的变量
2. unknown 是 顶级类型,任何类型的值(never除外)都可以赋值给该类型的变量
3. any 是顶级类型,任何类型的值(never除外)都可以赋值给该类型的变量,也是所有类型的子类型,any相当于关闭类型检测

JS的7个原始类型

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

说明
1.默认情况下 nullundefined 是所有类型的子类型。 可以把 null 和 undefined 赋值给其他类型。

如果你在tsconfig.json指定了"strictNullChecks":true ,null 和 undefined 只能赋值给 void 和它们各自的类型。

2.String是JavaScript中字符串包装类

Array数组

//明确指定数组的类型注解写法1
let arr:string[] = ["1","2"];
//明确指定数组的类型注解写法2 泛型写法
let arr2:Array<string> = ["1","2"]

object、Object 和 {}

语法:{属性名:属性值,属性名:属性值....}
说明
1.属性个数名字必须一模一样,不能多不能少
2.分割符分号和逗号可以,换行可以省略分号,因为JS中换行会自动添加分号,最好使用逗号。
3.object、Object 和 {}

  • Object 代表所有拥有 toStringhasOwnProperty 方法的类型,所有原始类型、非原始类型都可以赋给 Object。在严格模式下,null 和 undefined 类型也不能赋给 Object。
  • {}等价于Object
  • object 则表示非原始类型
let info: object = {
      name: 'why',
      age: 18
    }
info = [1,2,3]; //非原始类型
console.log(info);
info = 123; //报错

4.类型不注解,默认为any


以下写法,在实际开发中并不会使用,因为object并不清楚里面的属性是什么类型,获取到对象里的属性会报错。

//不使用
let info: object = {
  name: 'why',
  age: 18
}
console.log(info['age']) //报错

/*
写法1
let info: {
name:string
age:number
}
写法2
let info: {name:string;age:number}
写法3
let info: {name:string,age:number}
*/
let info: {
name:string
age:number
} = {
  name: 'why',
  age: 18
}
可选属性 ? 和 可选链运算符?.

可选属性?
如果某一属性不确定,可以使用?标识该属性可选
语法:{属性名:属性值,属性名?:属性值}

可选链运算符?.
?.用来判断左侧的表达式是否是 null | undefined,如果是则会停止表达式运行,可以减少我们大量的&&运算。

a === null || a === void 0 ? void 0 : a.b;
function getData(data: any){
	let name = data?.row?.name //data && data.row ? data.row.name:undefined
}
//普通写法
function getData(data: any){
	let name;
	if (data && data.row) {
		name = data.row.name
	}
}

比如我们写出a?.b时,
理解1:a ? a.b :undefined
理解2:如果a为null或者undefined,则后面的表达式等于没有,如果存在则获取a.b

访问属性的时候可以用可选链,但是赋值时不可以使用比如: xxx?.xxx=xxx

function函数

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

1.匿名函数 - 大多数时候不需要类型注解
当一个函数出现在TS可以确定该函数会被如何调用的地方时,该函数的参数会自动指定类型,最好不要加类型注解

const names = ['abc', 'cba', 'nba']
// 根据上下文环境推导出来的,这个时候可以不添加类型注解
// 上下文中的函数,可以不添加类型注解
names.forEach(function (item,index,arr) {
  console.log(item,index,arr)
})

这是因为TypeScript会根据forEach函数的类型以及数组的类型推断出item的类型;
这个过程称之为上下文类型(contextual typing),因为函数执行的上下文可以帮助确定参数和返回值的类型;

TS类型: any类型 | unknow类型

1.在 TypeScript 中,任何类型都可以被归为 any 类型,因此any 类型也是类型系统的顶级类型。
2.变量如果在声明的时候,未指定其类型,会被识别为任意值类型。
3.unknownany一样,所有类型都可以分配给unknown ,都表示不清楚是类型。

unknown 是 top type (任何类型都可以赋值给unknow类型) , 而 any 既是 top type, 又是 bottom type (任何类型都可赋值给any类型的变量,any类型可以赋值给任何类型) 。

区别 赋值 描述
any any上访问任何属性都是允许的,也允许调用任何方法 any 类型可以赋值给任意类型 any相当于关闭类型检验
unknow 默认情况下unknow类型上不能访问属性和调用方法(执行任何操作?),必须进行类型校验(缩小)才可以执行对应操作 unknow 类型只能赋值给 any 和 unknow 类型 unknow是更加安全的any,会进行类型检测
let foo:unknown = 'aaa'//合法
foo = 123 //合法
console.log(foo);//合法
console.log(foo.length); //非法
//类型缩小
if(typeof foo ==="string"){
console.log(foo.length); //合法
}

TS类型: void类型

当函数没有返回值,则返回void类型

function foo (num1:number,num2:number):void{
    console.log(num1+num2)
    return undefined
    //null也可以
    return null
}
/*
foo的类型是()=>void 表示是一个返回void的函数类型
const类型推导,推导出来是字面量类型
const height = 1.88 //1.88为heigth的类型,1.88是字面量类型
const height:1.88 //等价于
*/
const foo = () =>{}
//等价于
type FooType = () => void
const foo:FooType = ()=>{}

说明
1.可以返回null和undefined,因为默认情况下nullundefined是所有类型的子类型。
2.方法没有返回值将得到undefined,但是需要定义成void类型,而不是undefined类型,否则将报错。
3.当基于上下文的类型推导推导出返回类型为void的时候,并不会强制函数一定不会返回内容。(了解)
TypeScript 学习笔记 环境安装-类型注解-语法细节-类-接口-泛型,TypeScript/JavaScript,typescript,学习,笔记

let names:Array<string> = ['arr1','arr2']
names.forEach((item,index,arr)=>{
    return 123;//没有意义但是不会报错
})

TS类型:never类型 (几乎不用)

开发中很少使用never类型
never表示永不存在的值
①函数抛出异常,函数不会执行完毕并返回
②函数中执行无限循环的代码,使得程序永远无法运行到函数返回值那一步,永不存在返回。

新版本已经修改,类型推导出来是void

function foo(){
while (true) {}
}
function bar(){
  throw new Error()
}

never的使用场景

//封装工具/框架
function handleMessage(message: string | number ) {
  switch (typeof message) {
    case 'string':
      console.log('string处理方式处理message')
      break
    case 'number':
      console.log('number处理方式处理message')
      break
    default:
      const check: never = message //这一步永远来不到
  }
}

handleMessage('abc')
handleMessage(123)
//另外一个人调用这个函数传入布尔类型,函数定义参数部分添加boolean类型,check:never位置报错,就会发现case少了一个布尔类型

TS类型:Tuple(元组)

元组类型表示一个已知元素数量和类型的数组(固定长度和类型的数组),各元素的类型不必相同。

数组中通常建议存放相同类型的元素,不同类型的元素是不推荐放在数组中。如果不同类型放在数组中,取值时并不清楚每个元素的具体类型。

使用元组类型的好处
1.元组数据结构中可以存放不同的数据类型,取出来的item也有明确的类型
2.减少对象key的使用

let x: [string, number] = ['hello', 10];
console.log(x[0])

//类型推导:(string|numbner)[] ,取值并不清楚每一个元素是什么类型
let y = ['hello',10]

使用场景:当函数需要返回多个值的时候

function useState<T>(state: T) {
  // T 泛型
  let currentState = state
  const changeState = (newState: T) => {
    currentState = newState
  }
  const tupple: [T, (newState: T) => void] = [currentState, changeState]
  return tupple //返回值为[参数,函数]
}

const [
  counter, // number
  setCounter // (newState: number) => void
] = useState(10)

setCounter(1000)

const [
  title, // string
  setTitle //  (newState: string) => void
] = useState('abc')

const [
  flag, // boolean
  setFlag //  (newState: boolean) => void
] = useState(true)

语法细节

1.联合类型 | 和交叉类型 &

联合类型:取值可以为多种类型中的一种,使用 | 分隔每个类型
交叉类型: 一般用于多种对象类型取交集 ,使用& 分隔

let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven'; // OK
myFavoriteNumber = 7; // OK

说明
1.联合类型中的每一个类型被称之为联合成员(union’s members)
2.通常配合缩小联合一起使用

function printId(id:number|string){
	if(typeof id === 'string'){
	//缩小范围
	}else{
	}
}

交叉类型使用场景

interface Person {
	name:string
	age:number
}
interface Fans {
	name:string
    like:string
}
const Women :Person&Fans = {
    name:"ranran",
    age:18,
    like:'study'
}
2.type和interface接口作为类型声明

type 用于定义类型别名 (type alias)

//使用type声明对象
type IDType = string | number | boolean
//分号和逗号可以
type PointType = {x: number,y: number}
type PointType = {x: number;y: number}

type PointType = {//换行可以省略分号,因为js中换行会自动添加分号
  x: number
  y: number
}

接口可以看成规则,实现接口就必须满足接口设置的规则
语法 interface 接口名

//使用借口来声明对象
interface PointType{
    x:number
    y:number
}
interface PointType{
	z:number
}
//多次声明需要都满足
const obj:myInterface = {//obj对象必须满足接口的规则有name和age
	x:1,
	y:2,
	z:3
}

类型别名与接口的区别

- 相同点 不同点
别名 1.类型别名和接口非常相似,在定义对象类型时,大部分时候可以任意选择使用。
2.接口中几乎所有的特性都可以在type中使用
1.使用范围更广
2.不允许同名声明两次(报错)
接口 1.只能声明对象
2.可以多次声明同一个接口名称,属性叠加

开发常用:其他数据类型常用type,对象常用interface因为可扩展性更强

接口的继承extends

接口支持多继承

interface Person {
	name:string
	age:number
}
interface Fans extends Person{
    like:string
}
3.类型断言 as 和非空类型断言

类型断言:TypeScript 无法获取具体的类型信息,但是开发员自己清楚,就可以显式告诉TS
非空类型断言: !表示在此处告诉编译器,不会为nullundefined

// message -> undefined | string
function pringMessage(message?: string) {
  console.log(message!.length) //显式告诉不为空,如果不这样写会报错,因为message可能为空
}

pringMessage('Hello World')
pringMessage()
4.字面量类型和类型缩小

可以联合多个类型,类似于枚举的作用

//left right center分别是一个字面量
type Alignment = 'left' | 'right' | 'center'
let align:Alignment = //从上述字面量中选择一个

字面量本身就是string类型,所以对象在进行推理时会把options里的属性推理为string类型

type Method = 'GET' | 'POST'
type requestInfo= {
  url: string
  method: Method
}

//其他细节
function request(url: string, method: Method) {}
//报错的情况
const options= {
	url: 'http://www.coderwhy.org/abc',
	method: 'POST' // 类型推导,推导出来 options.method 是 string 类型
 }
request(options.url, options.method) // 第二个参数报错
options.method = '123' // 存在安全隐患 
//解决方案1,优选
const options: requestInfo= {
	url: 'http://www.coderwhy.org/abc',
	method: 'POST'
}
//解决方案2:进行类型断言(但是不方便别人维护时阅读)
request(options.url, options.method as "post") 
//解决方案3:设置options的时候就确定类型
const options:{url:string,methond:'POST'}= {
	url: 'http://www.coderwhy.org/abc',
	method: 'POST' 
 }

//解决方案4:tips写法
const options = {
  url: 'http://www.coderwhy.org/abc',
  method: 'POST'
} as const //把属性变成字面量,仅读

request(options.url, options.method)

类型缩小: 变量有一个确定的类型,在使用时对其类型做更小的类型限制,使得代码更加安全

  • typeof
  • 平等缩小(一些等号相关) instanceof
  • in(用于确定对象是否具有带名称的属性,如果指定的属性在指定的对象或其原型链中,则in 运算符返回true)
// 1. typeof 的类型缩小
type IDType = number | string
function printID(id: IDType) {
  if (typeof id === 'string') {
    console.log(id.toUpperCase())
  } else {
    console.log(id)
  }
}

// 2. 平等的类型缩小 (=== == !== !=/switch)
type Direction = 'left' | 'right' | 'top' | 'bottom'
function printDirection(direction: Direction) {
  //下面这串代码可以省略了
  //1. if 判断
  // if (direction === 'left') {
  //   console.log(direction)
  // } else if() {}
  // 2. switch 判断
  // switch(direction) {
  //   case 'left':
  //     console.log(direction);
  //     break
  //   case ...
  // }
}

// 3. instanceof
function printTime(time: string | Date) {
  if (time instanceof Date) {
    console.log(time.toUTCString())
  } else {
    console.log(time)
  }
}

class Student {
  studying() {}
}

class Teacher {
  teaching() {}
}

function work(p: Student | Teacher) {
  if (p instanceof Student) {
    p.studying()
  } else {
    p.teaching()
  }
}

// 4. in
interface Fish  {
  swimming: () => void
}
interface Dog  {
  running: () => void
}

function walk(animal: Fish | Dog) {
  if ('swimming' in animal) { //不能用.运算符时可以考虑in
    animal.swimming()
  } else {
    animal.running()
  }
}

const fish:Fish  = {
  swimming() {
    console.log('swimming')
  }
} 
5.函数的类型和函数签名
函数表达式

编写函数类型的表达式(Function Type Expressions),来表示函数类型

函数类型表达式:(参数列表) => 函数返回值类型

function calc(
  n1: number,
  n2: number,
  fn: (num1: number, num2: number) => number
) {
  return fn(n1, n2)
}


const result1 = calc(20, 30, function (a1, a2) {
  return a1 + a2
})
console.log(result1) // 50

//这里虽然只传入一个参数,但是不会报错
const result2 = calc(20, 30, function (a1) {
  return a1 //因为只使用了一个参数,所以可以只传入一个参数
})

console.log(result2) // 600

对于传入为函数类型的参数,当实参小于形参时不会报错会自动省略多余形参
可以想象匿名参数forEach,使用时并不是所有形参都传进去了

函数调用签名:支持声明属性

函数本身可以调用,并且函数也是一个对象,是对象就有属性。

格式:(参数列表):返回值类型 用于对象内
作用:描述带谁能够的函数,可以在一个对象类型中写一个签名,签名的作用是表示这是一个函数可以被调用

interface Bar{
  name:string
}
//不会报错
const bar:Bar =(num1:number):number =>{
    return 123
}
//调用时报错此表达式不可调用,因为bar的类型是Bar,并不知道其是一个函数可以被调用
bar()

//函数调用签名
interface Bar{
  name:string
  (num1:number):number
}
const bar:Bar =(num1:number):number =>{
    return 123
}
bar(123)

如果仅描述一个函数可以被调用,使用函数表达式。如果在描述函数作为对象可以被调用,同时也有其他属性时,使用函数调用签名。

构造签名(理解)

JavaScript函数也可以使用new操作符调用,当被调用时,TS会认为这是一个构造函数,因为产生了一个新的对象。

function foo(){
}
//可以new 但是不知道f的类型,会推断f为any
const f = new foo()

//问题:如何表达fn是一个构造函数,不是一个普通函数
function factory(fn){
  return new fn()
}
//解决:使用构造函数签名
class Person{ 
}
interface ICTORPerson{//符合当前规则的函数就是构造函数,可以通过new
  new():Person //new调用后的返回值是Person的示例,相当于这个函数new了之后返回Person示例
}
function factory(fn:ICTORPerson){
  const f = new fn()
  return f
}
factory(Person)
6.函数的重载和this类型
函数的重载(通用库和工具中使用较多)

函数的重载:函数的名称相同,但是参数不同的几个函数,就是函数的重载

实现需求: 如果我们编写了一个add函数,希望可以对字符串和数字类型进行相加
解决办法: 编写不同的重载签名(overload signatures)来表示函数可以以不同的方式进行调用

  //需求:如果我们编写了一个add函数,希望可以对字符串和数字类型进行相加
  //错误写法
  type AddType = number | string
  function add(a1: AddType, a2: AddType) {
     return a1 + a2  //报错AddType和AddType类型不能相加
   }
  /*写法1联合类型的缺点
  1.进行很多逻辑判断
  2.返回值的类型不能确定
  */
  function add(a1: number | string, a2: number | string) {
    if (typeof a1 === 'number' && typeof a2 === 'number') {
      return a1 + a2
    } else if (typeof a1 === 'string' && typeof a2 === 'string') {
      return a1 + a2
    }
  }

实现方法:一般是编写两个或者以上的重载签名,再去编写一个通用的函数以及实现
调用时根据传入的参数类型决定执行函数体时,执行哪一个函数的重载签名;

注意点:

  1. 重载签名没有函数体卸载通用函数之前
  2. 通用函数不能被调用
//1.2一起构成函数重载
//1.重载签名,不需要函数体
function add(num1: number, num2: number): number
function add(num1: string, num2: string): string
//2.通用的函数实现 ,通用函数不能被直接调用
function add(a1: any, a2: any) :any{
  return a1 + a2 
}

联合类型和函数重载都可以实现一个功能时,优先选择联合类型,联合类型不能实现时再选择函数重载

this类型(很少使用)

没有对js进行特殊配置时,this的默认类型是any

  const info = {
    name: 'why',
    eating() {
      console.log(this.name + ' eating')
    }
  }
  info.eating()
  function foo(){
    console.log(this)
  }
  foo()

tsc --init 初始化配置文件tsconfig.json

当这个参数为true时,TypeScript会根据上下文推导this,但是不能正确选择时,就会报错,需要明确指定this的类型。
指定规则: 函数的第一个参数,参数名必须是this,其他参数从第二个开始传递,编译成js代码是第一个参数会被删除。

//this配置:没有模糊不明确(比如any,所以配置之后上述代码会报错)的this
noImplicitThis:true

//显式指定this的类型,将this作为函数的第一个参数,名字必须是this
type ThisType = { name: string }
function eating(this: ThisType, message: string) {
  console.log(this.name + ' eating', message)
}
const info = {
  name: 'why',
  eating
}
// 显式绑定
eating.call({ name: 'kobe' }, '呵呵呵')
eating.apply({ name: 'james' }, '嘿嘿嘿 ')

this相关的内置工具(了解)

TypeScript提供一些工具类来辅助进行常见的类型转换,这些类可以全局使用。

  • ThisParameterType<>:用于提取一个函数类型Type的this参数类型,没有this参数返回unknown
  • OmitThisParameter<>:移除Type的this参数类型,并返回当前的函数类型
  • ThisType<>:用于绑定上下文的this类型(piana里的getters和action,讲的很奇怪,先记下来)
type ThisType = { name: string }
  function eating(this: ThisType, message: string) {
    console.log(this.name + ' eating', message)
  }

//获取函数eating的类型:type ty = (this: ThisType, message: string) => void
type ty =  typeof eating
//提取出函数里面this的类型type eatingThisType = {name: string;}
type eatingThisType = ThisParameterType<ty>
//type pureEatingType = (message: string) => void
type pureEatingType = OmitThisParameter<ty>

interface IState{
    name:string,
    age:number
}  
interface IStore{
  state:IState,
  eatting?:()=>void,
}
//给store绑定上下文this到IState
const store:IStore & ThisType<IState>  = {
  state:{
    name:"ranran",
    age:18
  },
  eatting:function(){
    console.log(this.name)//如果没绑定获取到的应该是store的this里面没有name属性,需要使用this.state.name获取。当很多函数使用到this.state里面的属性时代码会很冗余,将store的this绑定到IState之后,this就从state里面取name。
  }
}
7.函数的参数
  • 必传参数 -> 有默认值的参数 -> 可选参数
可选参数

使用指定某个参数是可选的,类似于可选属性

//可选参数的类型:number | undefined
//y -> undefined | number
function foo(x: number, y?: number) {
    console.log(x, y)
}
foo(20, 30)
foo(20)
默认参数
  • 有默认值的情况下,类型注解可以省略
  • 有默认值的参数是可以接受undefined类型,不写时相当于传入了undefined,当ts发现接受到undefined就给参数赋默认值(了解即可,使用时认为是指定的,不是联合的)
// 必传参数 -> 有默认值的参数 -> 可选参数
function foo(x: number, y: number = 100) {
  console.log(x, y)
}
//省略类型注解的情况
function foo(x: number, y = 100) {
  console.log(x, y)
}

foo(20) // 20 100
剩余参数

剩余的参数会被封装成一个数组

function sum(initalNum: number, ...nums: number[]) {
  let total = initalNum
  for (const num of nums) {
    total += num
  }
  return total
}

console.log(sum(20, 30))
console.log(sum(20, 30, 40))
console.log(sum(20, 30, 40, 50))

TypeScript 类的使用

类的特性

ES6的class可以看作只是一个语法糖,看成构造函数的另一种写法,所以类可以看成是一个有构造签名的函数。

//案例1
class Point{}
typeof Point //'function'
Point === Poin.prototype.constructor //true
//案例2 类可以看成是一个有构造签名的函数
class Person{};
//表示stor是一个函数类型,并且是一个构造函数
function factory(stor: new()=> void){}
factory(Person)
//案例2的写法2
class Person{};
interface ty{
    new():void
}
//表示有构造签名的
function factory(stor: ty){}
factory(Person)
  • static静态属性(方法)/类属性(方法):不需要创建实例就可以使用,是属于类的通过类名.属性(方法)调用
  • 实例属性(方法):是属于实例化出的这个对象,通过对象.属性(方法)调用
  • 类的所有方法都定义在类的prototype属性上
  • 实例属性除非显式定义在本身(this),其余都是定义在原型上

1.成员属性必须先声明

class Person{
  //1.成员属性必须要先声明
  name:string = ""; //可以类型注解和设置初始化值
  age:number
  constructor(name:string,age:number){
    this.name = name
    this.age = age
  }
}
const p1 = new Person("ranran",18)
const p2 = new Person("biubiu",18)

2. 类的成员修饰符

成员修饰符 描述 范围
public(默认值) 属性为共有属性 任意位置访问和修改
protected 属性为保护属性 此类和其子类中(子类实例也不可以)访问和修改
private 属性为私有属性 只能在此类里访问和修改

3.可见修饰符的构造器语法糖(参数属性)
TypeScript提供特殊的语法参数属性: 可以将构造函数参数转换成一个同名同值的类属性

1.创建声明同名的成员属性
2.可见修饰符修饰成员属性(权限 | readonly)

//完整写法
class Person{
	public name:string; 
	constructor(name:string){
		this.name = name;
	}
}
//简洁写法
class Person{
	constructor( public name:string){
		this.name = name;
	}
}

4.在TypeScript可以使用存取器使私有属性被外界访问

  • get 属性名(){} 表示getter方法,在属性被读取时自动调用
  • set 属性名(){} 表示setter方法,在属性被修改时自动调用
class Person{
	private _name:string; //私有属性:属性前面使用_(习惯约定)如果没有写下划线,在读取/修改该属性时并不知道访问的是属性name还是方法name
	constructor(name:string){
		this._name = name;
	}
	get name(){
		return this._name
	}
	set name(value){
		this._name = value;
	}
}
const per = new Person("ranan");
console.log(per.name);//读取属性自动调用get name(){}
per.name = "biubiu"; //修改属性set name(){}

5.成员修饰符readOnly只读
readonly属性:表示该属性只读不可以修改,和static连用需要放在其后面

class Person{
	name:"ranan" //定义实例属性
	readonly age:15 //定义只读属性
	call(){} //定义实例方法
}

6.TS类型检测:鸭子类型
TS类型检测:鸭子类型(走得像鸭子声音像鸭子就是鸭子)
鸭子类型:只关心属性和行为是否一样,并不关心是不是具体对应的类型

//情况1:不会被报错
makeArea({getArea:()=>{}})
//情况2
class A {
  name:"ranran"
}
class B{
   name:"ranran"
}
const a:A = new B();

抽象类abstract

抽象类:多个方法有共同方法,但是实现方式有差别。可以将同名方法抽离到父类,由子类去实现抽象方法

  • abstract修饰类 - 抽象类
    • 抽象类不能被实例化,只能被继承
    • 抽象类中可以有抽象方法,也可以有普通方法
  • abstract修饰方法 - 抽象方法
    • 抽象方法只能被定义在抽象类中,子类必须重写抽象类
    • 抽象方法没有方法体
//多态的体现:父类的引用指向子类
function makeArea(shape: Shape) {
  return shape.getArea()
}

abstract class Shape { //抽象类
  abstract getArea() //抽象方法
}

class Rectangle extends Shape {
  private width: number
  private height: number
  constructor(width: number, height: number) {
    super()
    this.width = width
    this.height = height
  }

  getArea() {
    return this.width * this.height
  }
}

class Circle extends Shape {
  private r: number
  constructor(r: number) {
    super()
    this.r = r
  }

  getArea() {
    return this.r * this.r * 3.14
  }
}

const rectangle = new Rectangle(20, 30)
//此时makeArea方法的形参是Shape的子类
console.log(makeArea(rectangle))

const circle = new Circle(10)
console.log(makeArea(circle))

TypeScript对象类型

  • ?可选属性
  • readonly 只读属性
  class Person{
    name?:"ranran"
    readonly age:15
  }

索引签名

索引签名:可以通过索引访问[标识符自己起:通过什么索引访问]:索引访问之后返回值的类型
使用场景:不知道具体的实现是什么样的,但是知道具备某种特性

说明

  • 一个索引签名属性的类型必须是string或者number其中一个
  • 数字类型索引的类型必须是字符串类型索引的子类型

原因:所有数字类型访问索引时最终都是转换为string类型访问的,如果同时设置了,数字类型0拿到的类型需要符合字符串类型’0’拿到的类型

//案例1
interface IndexLanguage {
	[index:number]:string //通过number索引访问,访问之后返回string类型数据
	//这里定义的属性也得满足索引签名的要求
	//如果需要两种类型,需要分开写(语法不支持)
	 [index:string]:string 
}
function getInfo():IndexLanguage {} //不知道具体的实现是什么样的,但是知道具备某种特性
const frontLanguage = getInfo()

//案例2
interface IPerson {
  //告知通过索引获取到的数据类型是什么样
  [index:string]: string
}
//报错原因 ["biu","ranran"]通过字面量创建的Array实例 =>数组中自带了很多其他属性比如name.forEach返回值是Function不是string
const name:IPerson = ["biu","ranran"]

函数签名

interface来定义对象中普通的属性和方法的,实际上它也可以用来定义函数类型(除非特别的情况,推荐使用类型别名来定义函数)

// type CalcFn = (n1: number, n2: number) => number

// 可调用接口
interface CalcFn {
  (n1: number, n2: number): number
}

function calc(num1: number, num2: number, calcFunc: CalcFn) {
  return calcFunc(num1, num2)
}

const add: CalcFn = (num1, num2) => num1 + num2
calc(20, 30, add)

TypeScript接口

类实现接口 implements

接口可以看成规则,对类进行约束

说明

  • 接口只定义对象的结构,而不考虑实际值
  • 在接口中所有的方法都是抽象方法

定义类时可以使类去实现一个接口(满足接口定义的规则),一个子类只能有一个父类,但是可以实现多个接口

interface myInterface{ //接口定义必须有name和sayHello
	name:string,
	sayHello():void; 
}
class MyClass implements myInterface{
	name:stringconstructor(name:string){
		this.name = name;
	}
	sayHello(){} //类的实现
}

抽象类和接口的区别

区别 抽象类 接口
继承 抽象类是类,一个类只能继承一个抽象类 一个类可以实现多个接口
方法 可以是普通方法和抽象方法 全是抽象方法
子类 子类必须覆盖抽象类的抽象方法 子类必须遵守接口定义的规则,接口中的所有东西都得有

抽象类是对类本质的抽象,表达的是 is a 的关系。比如:male is a Human。抽象类包含并实现子类的通用特性
接口是对行为的抽象,表达的是 like a 的关系。比如:Baoma like a plane(它有飞的功能一样可以飞),但其本质上 is a Car。接口的核心是定义行为,即实现类可以做什么

特殊:严格字面量赋值检测

第一次创建的对象字面量被表示为新鲜的,对于新鲜的字面量会进行严格的类型检测(必须完全满足类型的要求,不能有多余的属性)。
当一个新的对象字面量分配给一个变量或传递给一个非空目标类型的参数时,对象字面量指定不存在的属性是错误的。

name: string
   age: number
}
  
const p: IPerson = { //第一次创建新鲜的,被严格的检测
    name: 'why',
    age: 18,
    height: 1.88//报错,Iperson接口没有height
}
  
const info = { //第一次创建新鲜的,被严格的检测
    name: 'why',
    age: 18,
    height: 1.88 
}
// freshness 不是新鲜的不严格检测
const p2: IPerson = info // 不报错  

TypeScript枚举类型

格式:enum 枚举类型标识符 {}文章来源地址https://www.toymoban.com/news/detail-566673.html

enum Color {//没设置值,初始值默认从0开始按顺序自增,可以理解为数组下标
  RED,
  PINK,
  BLUE="blue",//设置初始值
}
const pink: Color = Color.PINK;
console.log(pink); // 1

到了这里,关于TypeScript 学习笔记 环境安装-类型注解-语法细节-类-接口-泛型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • TypeScript 学习笔记(一):基本类型、交叉类型、联合类型、类型断言

    TS中实现对象属性必选、对象属性在开发过程中十分常见,前端在传参数时,有些参数比必传,有些是选传,我们可以定一个多个对象来实现传参,但是这让代码变得冗余。我们可以通过TS定义数据类型来实现。 TypeScript中文网 1. 数组 2. 布尔 3. 数值 当我们给num赋值为123但没有

    2024年02月15日
    浏览(35)
  • 【wow-ts】前端学习笔记Typescript基础语法(一)

    项目地址是https://github.com/datawhalechina/wow-ts。 我选择的是ts前端课程 第一次接触ts,先去了解了下ts的内容,复制内容如下 TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准(ES6 教程)。 TypeScript 由微软开发的自由和开源的编程语言。 TypeScript 是一种给 JavaScript 添加特性的

    2024年01月16日
    浏览(46)
  • TypeScript 学习笔记(二):接口与类型别名、字面量类型

    在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些

    2024年02月16日
    浏览(28)
  • 最新 Vue3、TypeScript、组合式API、setup语法糖 学习笔记

    备注:目前 vue-cli 已处于维护模式,官方推荐基于 Vite 创建项目。 vite 是新一代前端构建工具,官网地址:https://vitejs.cn vite 的优势如下: 轻量快速的热重载(HMR),能实现极速的服务启动。 对 TypeScript 、 JSX 、 CSS 等支持开箱即用。 真正的按需编译,不再等待整个应用编译

    2024年02月20日
    浏览(36)
  • TypeScript教程(二)基础语法与基础类型

    TypeScript由以下几个部分组成 1.模块 2.函数 3.变量 4.语句和表达式 5.注释 示例: Runoob.ts 文件代码: 以上代码首先通过  tsc  命令编译: Runoob.js 文件代码:  最后我们使用 node 命令来执行该 js 代码。 tsc 常用编译参数如下表所示: 序号 编译参数说明 1. --help 显示帮助信息

    2024年02月12日
    浏览(30)
  • 【TypeScript】进阶之路语法细节,类型和函数

    类型别名(type)的使用 为解决给联合类型的类型定义过长的问题 使用类型别名 接口(interface)的声明的使用 使用interface声明 相比较类型别名,少了= 二者区别: 类型别名和接口声明非常相似,在定义对象的时候,可以任意选择使用 主要区别: type类型使用范围更广 type定

    2024年02月13日
    浏览(32)
  • 【Python】类型注解 ⑤ ( Union 联合类型注解 | Union 联合类型语法 | 普通 / 容器 变量设置 Union 联合类型注解 | 函数设置 Union 联合类型注解 )

    对 list 列表 或 dict 字典 类型 设置 类型注解 , 如果 list 列表中的元素都是 int 类型 , dict 字典 中的 键值对 , 键 Key 类型是 str 字符串类型 , 值 Value 的类型是 int 数字类型 , 那么 , 可以写成下面的形式 ; 假如 list 列表 中的 元素类型不是 int 类型 , 而是 str 类型 或 int 类型 , 如下

    2024年02月10日
    浏览(38)
  • 【Unity】Unity Shader学习笔记(四)创建和使用、基本语法、属性基本类型、数值精度

    由于着色器是依赖于材质的,所以创建着色器之前通常要先创建一个材质(Material)。然后再创建一个Shader。 结果如下: 然后给材质指定Shader,再给物体指定材质。 建好Shader后双击打开,通常默认使用vs studio开发shader。一个Shader主要的内容都是写在 Shader {} 代码块中,其中包

    2024年02月16日
    浏览(34)
  • 前端TypeScript学习day03-TS高级类型

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹)            目录 TypeScript 高级类型 class 类 class继承  extends implements  类成员可见性  public  protected  private   readonly 兼容性 类型兼容性 接口兼容性  函数兼容性  TypeScri

    2024年02月08日
    浏览(27)
  • 前端TypeScript学习day02-TS常用类型

    (创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 TypeScript 常用类型 接口  元组  类型推论 类型断言 字面量类型 枚举 any 类型 typeof  当一个对象类型被多次使用时,一般会使用接口(interface)来描述对象的类型,达到

    2024年02月08日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包