TypeScript学习--day1

一、介绍

TypeScript是JS的超集,为JS添加了类型支持。

1.1 为什么添加类型支持

JS代码的错误大部分是类型错误,增加改Bug时间,影响开发效率。

静态类型:编译期做类型检查 

动态类型:执行期做类型检查

TS--静态类型编程语言,代码执行时发现错误

JS--动态类型编程语言,代码编译时发现错误

 1.2 TS的优势

  1. 减少改Bug时间,提升开发效率
  2. 类型系统提升代码的可维护性,重构代码更容易
  3. 支持ECMAScript语法
  4. 类型推断机制,自动根据代码逻辑推断数据类型

二、使用

2.1 安装使用

npm i -g typescript

tsc -v --验证是否安装成功

2.2 初体验

创建hello.ts文件

tsc hello.ts --将TS编译为JS

node hello.js --执行JS代码

2.3 简化运行步骤

每次修改代码都要编译成JS在执行,太麻烦

npm i -g ts-node

ts-node hello.ts --在内部隐式转换成JS,不生成JS文件

三、常用类型

3.1 类型注解

let age: number = 18

约定类型必须和赋值类型一致

3.2 常用基础类型

3.2.1 JS已有类型

基础类型  Undefined | Number | Bigint | String |  Boolean | Symbol

引用类型 Object(Array) | Function

3.2.2 TS新增类型

联合类型、自定义类型、接口、元组、字面量、枚举、void、any

3.3 原始类型

number / string / boolean / null / undefined / symbol

这些类型按照JS中类型名称书写

let age: number = 18
let isLoading: boolean = false

3.4 数组类型

两种写法

let numbers: number[] = [1, 3, 5]
let strings: Array<string> = ['a', 'b', 'c']

如果一个数组有两个或以上类型,即联合类型

let mergeArr: (number | string)[] = [1,'a',3,'b']

//如果不添加括号 表示这个变量可以是number也可以是string数组
let x: number | string[] = ['a','b']
let y: number | string[] = 10

3.5 类型别名

当同一类型被多次使用时,类型别名可以简化书写

关键字type

type CustomArray = (number | string)[]

let arr1: CustomArray = [1, 'a', 3]
let arr2: CustomArray = ['x', 'y', 2]

3.6 函数类型

函数类型指的是参数类型和返回值类型

3.6.1 单独指定参数、返回值的类型

//函数声明
function add(n1: number, n2: number):number{
    return n1 + n2
}

//函数表达式
const add = (n1: number, n2:number):number => {
    return n1 + n2
}

3.6.2 同时指定参数、返回值的类型

const add: (n1: number, n2: number) => number =  (n1, n2) => {
    return n1 + n2
}

3.6.3 如果函数没有返回值,声明为void

function greet(name: string): void{
 console.log('Hello', name)
}

3.6.4 可选参数

参数名后面加问号,可选参数只能出现在列表最后,也就是可选参数后面不能再出现必选参数

function introduction(name: string, age?: number): void{
    console.log(`我叫${name}`)
    if(age){
        console.log(`我今年${age}岁`)
    }
}

3.7 对象类型

  1. 直接使用{}来描述对象结构,属性采用属性名:类型的形式;方法采用方法名():返回值类型的形式
  2. 如果方法有参数,就在方法名后面的小括号指定参数类型greet(name:string):void
  3. 在一行代码中指定对象的多个属性类型时,使用;分隔
let person: {
    name: string, 
    age: number,
    // sayHi():void
    sayHi: () => void
} = {
    name:'Augustine',
    age:18,
    sayHi(){
        console.log(`hi! ${this.name}`)
    }
}

可选属性

给可选属性名后加问号,与函数可选参数类似

3.8 接口

3.8.1 用法

当一个对象类型被多次使用,一般使用接口来表述对象便于复用

interface IPerson {
    name: string, 
    age: number,
    sayHi: () => void
} 

let person1: IPerson = {
    name:'Mary',
    age:19,
    sayHi() {
        console.log(`${this.name}, Hi!`)
    },
}

type和interface

interface只能为对象指定类型

type可以为任意类型指定别名

 3.8.2 继承

如果两个接口有相同的属性或方法,可以将公共属性或方法抽离出来,通过继承实现复用

interface Point2D {x: number; y: number}
interface Point3D {x: number; y: number; z: number}

//可以写为

interface Point2D {x: number; y: number}
interface Point3D extends Point2D {z: number}

3.9 元组

使用number[]的缺点是无法确切知道数组长度

元组(tuple)确切知道包含多少个元素,以及特定索引对应的类型,少一个多一个都不行

let position [number, number] = [1, 2]

3.10 类型推论

TS中没有明确指出类型的地方,类型推论机制可以帮助提供类型

两种情况:

声明变量并初始化值

决定函数返回值

类型注解能省则省,提高开发效率

3.11 类型断言

指定更加具体的类型

当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型中共有的属性或方法

getElementById返回值的类型是HTMLElement,只包含所有标签的公共属性和方法

比如<a>可以拿到.id属性 但不能识别.href

通过as实现类型断言 后面跟一个更具体的类型

const aLink = document.getElementById('link') as HTMLAnchorElement

3.12 字面量类型

let str1 = 'hello' //类型为string
const str2 = 'hello' //类型为hello

常量的值不能变化,这里的“hello”就是一个字面量类型,即某个特定的字符串也可以成为TS中的类型,除此之外任意的JS字面量都可以作为类型使用

使用场景:表示一组明确的可选值

比如在贪吃蛇游戏里的方向只能是up、down、left、right中的一种

function selectDirection(direction: 'up' | 'down' | 'left' | 'right'){
    console.log(direction)
}

3.13 枚举类型

描述一个值,并定义一组命名常量,这个值可以是这组常量里任何一个。

  1. enum关键字定义枚举
  2. 枚举名称大写字母开头
  3. 枚举的多个值之间通过逗号分隔
  4. 使用这个枚举用枚举名称做类型注解
enum Direction{Up, Down, Left, Right}

function selectDirection(direction: Direction){
    console.log(direction)
}
//.访问枚举成员
selectDirection(Direction.Up)

枚举成员的默认值是从0开始自增的数字(数字枚举),也可以自行给枚举成员初始化值

字符串枚举:枚举成员的值是字符串,每个成员必须有初始值

enum Direction{
    Up = 'UP',
    Down = 'DOWN',
    Left = 'LEFT',
    Right = 'RIGHT'
}

//编译后的js代码
//生成一个立即执行函数并传入Direction(作为对象)
var Direction;
(function (Direction) {
    Direction["Up"] = "UP";
    Direction["Down"] = "DOWN";
    Direction["Left"] = "LEFT";
    Direction["Right"] = "RIGHT";
})(Direction || (Direction = {}));

一般推荐字面量+联合类型组合方式,因为枚举会被编译成函数,带来的开销更大。

3.14 any类型

不推荐使用,因为会让TS失去类型保护的优势

当一个值的类型为any,可以对该值进行任意操作,并且不会有代码提示。

隐式any情况:(不建议这样做)

  1. 声明变量不提供类型和初始值
  2. 函数参数不加类型

3.15 typeof

第一种用法与JS相同 获取数据类型

第二种用法:在类型注解中引用变量或属性的类型(简化类型书写),不能查询函数调用的类型

let p :{ x: number, y: number}
function formatPoint(point: typeof p){
    console.log(point)
}
formatPoint({x:2, y:5})

四、高级类型

4.1 class类

TS支持ES6中class关键字,用class创建的类也作为一种类型存在

4.1.1 基本使用

class Person{
    name: string
    age: number
    gender = 'male'
    //有初始值的属性可以省略类型注解

    constructor(name: string, age: number, gender?: 'male' | 'female'){
        //构造函数里不能指定返回值类型注解
        this.name = name
        this.age = age
        if(gender){
            this.gender = gender
        }
        
    }
}

const bob = new Person('bob', 18)
console.log(bob)

4.1.2 实例方法

class Circle{
    x: number
    y: number
    radius: number
    constructor(x: number, y: number, radius: number){
        this.x = x
        this.y = y
        this.radius = radius
    }
    //设置计算属性
    get area() {
        return Math.PI * this.radius ** 2;
      }
    //方法的类型注解与普通函数相同
    scale(n: number):void{
        this.radius *= n
    }
}

const c = new Circle(1, 2, 3)
console.log(c.area)//28.274333882308138
c.scale(3)
console.log(c.area)//254.46900494077323

4.1.3 类继承

extends (JS自带)

子类继承父类,子类的实例对象可以访问父类的属性和方法

class Animal{
    eat(){
        console.log('eat')
    }
}

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

const d = new Dog()
d.eat()
d.bark()

implements (TS特有)

强制类遵循特定的接口定义。当一个类实现了一个接口时,它必须实现接口中定义的所有属性和方法。

interface Shape {
    calculateArea(): number;
}

class Circle implements Shape {
    radius: number;

    constructor(radius: number) {
        this.radius = radius;
    }

    calculateArea(): number {
        return Math.PI * this.radius ** 2;
    }
}

let circle = new Circle(5);
console.log(circle.calculateArea()); // 输出圆的面积,约为 78.54

4.1.4 类成员可见性

可见性修饰符

public - 公有的,被修饰的属性或方法可以被任何地方访问(默认)

protected - 受保护的,仅对其声明所在类和子类中可见(在子类的方法内部可以通过this访问,实例对象不可见)

private - 私有的,只在当前类中可见,实例对象以及子类不可见

只读修饰符

readonly - 表示只读,用来防止在构造函数之外对属性进行赋值,不能修饰方法

  1. 使用readonly指定属性值一定要声明属性值的类型
  2. 可以用来声明接口的属性和对象属性

4.2 类型兼容性

两种类型系统

结构化类型系统(Structural Type System):按照属性和方法是否相同来比较两个类是否相同

标明类型系统(Nominal Type System):只看两个类的名称是否相同,即便内部结构完全相同也不能认为是同一种类型

TS采用结构化类型系统,而像C++、java采用标明类型系统。

4.2.1 类与接口的类型兼容性

class Point{
    x: number
    y: number
}
class Point2D{
    x: number
    y: number
}

//产生类型兼容性 不会报错
const p: Point = new Point2D()

更准确的说法:对于对象类型,如果A的成员是B的子集,则B可以赋值给A

class Point{
    x: number
    y: number
}
class Point3D{
    x: number
    y: number
    z: number
}

//产生类型兼容性 不会报错
const p: Point = new Point3D()

接口之间、类与接口之间的兼容性与类之间的相同。

4.2.2 函数的类型兼容性

考虑:参数个数、参数类型、返回值类型

参数个数-参数少的可以赋值给参数多的

参数类型-相同位置的参数类型要相同或兼容

interface Point2D{
    x: number
    y: number
}
interface Point3D{
    x: number
    y: number
    z: number
}

type F2 = (p: Point2D) => void
type F3 = (p: Point3D) => void

let f2: F2
let f3: F3

f3 = f2
f2 = f3 //不兼容

返回值类型-如果是基本类型,两个类型要相同;如果是对象类型,成员多的可以赋值给成员少的

4.3 交叉类型

&表示,组合多个类型为一个类型(常用于对象)

interface Person{
    name: string
}
interface Contact{
    phone: string
}

type PersonDetail = Person & Contact
let obj: PersonDetail = {
    name: 'alice',
    phone:'123456'
}

交叉类型与接口继承的不同:

接口继承中同名属性的类型不同会报错,而交叉类型对于同名属性类型会进行重载

interface A{
    fn: (value: number) => string
}
interface B{
    fn: (value: string) => string
}

type C = A & B
//则C中fn为
//fn: (value: string | number) => string

 4.4 泛型

4.4.1 泛型函数与泛型接口

在保证类型安全的前提下(不使用any)让函数支持多种类型的调用 ,从而实现复用,常用于:函数、接口、class

函数名称后加<>,它可以捕获调用函数时提供的数据类型,可以将其作为函数参数和返回值的类型

function id<Type>(value: Type):Type{
    return value
}
//在<>中指定具体的类型 就会被函数声明时指定的类型变量Type捕获到
const num = id<number>(10)
const str = id<string>('a')

数组在TS中就是一个泛型接口,使用数组时TS会根据数组的不同类型,来自动将类型变量设置为相应的类型

const str = ['a', 'b', 'c']
str.forEach(item => {
    //item 类型为 string
})

const nums = [1, 2, 3]
nums.forEach(item => {
    //item 类型为number
})

const mixArr = [1, 'a', 'w']
mixArr.forEach(item => {
    //item 类型为string | number
})

4.4.2 泛型类

class GenericClass<Type>{
    defaultValue: Type
    add: (x: Type, y: Type) => Type
}

const myNumClass = new GenericClass<number>()
myNumClass.defaultValue = 10

const myStrClass = new GenericClass<string>()
myStrClass.defaultValue = 'a'

4.4.3 泛型约束

因为事先不知道到底是哪种类型,所以直接访问泛型变量的属性或函数会报错,就像这样:

function loggingIdentity<T>(arg: T): T {
    console.log(arg.length); //类型T上不存在属性length
    return arg;
}

所以使用接口对泛型进行约束,只允许函数传入符合这个接口规则的变量:

interface Lengthwise {
    length: number;
}

//传入的变量必须包含length属性
function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
}

4.4.4 泛型工具类型

Partial<Type>--构造一个类型,将Type的所有属性设置为可选

interface Props{
    id: string
    children: number[]
}
type ParticalProps = Partial<Props>

下图为ParticalProps的真实类型

Readonly<Type>--构造一个类型,将Type的所有属性设置只读

interface Props{
    id: string
    children: number[]
}
type ReadonlyProps = Readonly<Props>

 Pick<Type, Keys> 从type中选择一组属性来构造新类型

  1. Type表示选择谁的属性,keys表示选择哪几个属性
  2. keys只能传入Type中包含的属性
interface Props{
    id: string
    title: string
    children: number[]
}
type PickProps = Pick<Props, 'id' | 'title'>

 Record<Keys, Type>--构造一个对象类型,属性键为keys,属性类型为type

type RecordObj = Record<'a' | 'b' | 'c', string[] | number>
//同义于
//type RecordObj = {
//     a: string[]
//     b: string[]
//     c: string[]
// }
let obj: RecordObj = {
    a: ['1'],
    b: ['2'],
    c: ['3']
}

4.5 索引签名类型

无法确定对象中有哪些属性时就需要索引签名

//表示key如果为string类型的属性名都可以出现在该对象中,并且属性值为number
interface AnyObject{
    [key: string]: number
}

数组对应的泛型接口,也使用了索引签名,下面模拟了原生的数组接口

//只要是number类型的键都可以出现在数组中
interface MyArray<T>{
    [n: number]: T
}

4.6 映射类型

4.6.1 基于联合类型创建映射

基于旧类型(联合类型)创建新类型,减少重复书写

type PropKeys = 'x' | 'y' | 'z'
type Type1 = { x: number; y: number; z:number}

//使用映射
type Type2 = {[key in PropKeys]: number}
  1. 映射类型基于索引签名类型
  2. key in PropKeys表示key必须和PropKeys联合类型中相同
  3. 使用映射类型创建的新对象类型Type2和Type1的结构完全相同
  4. 映射类型只能在类型别名中使用,不能在接口中使用

 4.6.2 基于对象类型创建映射

 也可以根据对象类型创建新类型

type Props = { a: number, b: string, c: boolean}
type Type3 = {[key in keyof Props]: number}
  1. keyof 是获取该对象所有键的联合类型即 'a' | 'b' | 'c'
  2. 然后 key in keyof Props表示key必须是Props和所有键名称相同

 4.6.3 使用映射实现Partical<Type>

 泛型工具类型都是基于映射类型实现的

//Partial<Type>实现 -- 让所有类型变为可选
type Partial<T> = {
    [P in keyof T]?: T[P]
}
  1. []后面添?表示将所有属性设置为可选
  2. T[P]表示获取T中每个键对应的类型 (索引查询)

 索引查询的用法

type Props = { a: number, b: string, c: boolean}
type TypeA = Props['a']//number
type TypeB = Props['a'|'b'] //number | string
type TypeC = Props[keyof Props] //number | string | boolean

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/541380.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

前端保留两位小数

一、保留两位小数&#xff08;四舍五入&#xff09; 解决方案&#xff1a;使用 toFixed(x) 方法可以对小数进行指定位数保留&#xff0c;其中x是要保留的位数用法&#xff1a;num.toFixed(x)&#xff0c;其中num为需要操作的数据&#xff0c;x为要保留的位数示例&#xff1a;1…

力扣LeetCode138. 复制带随机指针的链表 两种解法(C语言实现)

目录 题目链接 题目分析 题目定位&#xff1a; 解题思路 解题思路1&#xff08;粗暴但是复杂度高&#xff09; 解题思路2&#xff08;巧妙并且复杂度低&#xff09; 题目链接 138. 复制带随机指针的链表https://leetcode-cn.com/problems/copy-list-with-random-pointer/ …

双写一致性问题

双写一致性问题&#xff1a;同一份数据&#xff0c;需要写数据库、写缓存。数据库中的数据和缓存中的数据要一致 解决办法&#xff1a;延迟双删 当我们要进行更新操作时&#xff0c;先删除缓存&#xff0c;再更新数据库&#xff0c;延迟几百ms再删除一次redis的缓存数据。 示…

2023年蓝桥杯——日期统计

目录 题目链接&#xff1a;1.日期统计 - 蓝桥云课 (lanqiao.cn) 题目描述 思路 代码思路 定义数据结构&#xff1a; 处理每一个月&#xff1a; 检查日期序列在num100中是否存在&#xff1a; 计数匹配的日期数&#xff1a; 输出结果&#xff1a; 代码实现 总结 题目链…

【Python习题】某景区门票的优惠措施为:购买5张以内门票不打折,5到20张打九折,20张以上打八折。编写程序,根据购买的门票数量,输出总票价。

题干 某景区门票的优惠措施为:购买5张以内门票不打折&#xff0c;5到20张打九折&#xff0c;20张以上打八折。编写程序&#xff0c;根据购买的门票数量&#xff0c;输出总票价。 代码

介绍几个好用的电商(淘宝京东1688)API接口,可测试

以下是几个好用的电商&#xff08;淘宝、京东、1688&#xff09;API接口&#xff0c;这些接口都可以进行测试以确保其稳定性和可用性&#xff1a; taobao.item_get-获取淘宝商品数据接口返回值说明 1.请求方式&#xff1a;HTTP POST GET &#xff08;复制薇&#xff1a;Anzex…

2024.4.13 Python 爬虫复习day01

目录 day01_HTTP协议HTML页面web服务器 各类名词解释 URL统一资源定位符 HTTP协议 HTML页面 知识点: 第一个页面 标题标签和图片标签 注册页面 登录页面 WEB服务器 安装fastapi和uvicorn 原始命令方式 镜像源命令方式 工具方式 快速搭建web服务器 知识点: 示例…

CH254X 8051芯片手册介绍

1 8051CPU 8051是一种8位元的单芯片微控制器&#xff0c;属于MCS-51单芯片的一种&#xff0c;由英特尔(Intel)公司于1981年制造。Intel公司将MCS51的核心技术授权给了很多其它公司&#xff0c;所以有很多公司在做以8051为核心的单片机&#xff0c;如Atmel、飞利浦、深联华等公…

ARMv8-A架构下的外部debug模型之外部调试事件(external debug events)概述

外部调试器与处理器之间的握手与external debug events 一&#xff0c;External Debug的使能二&#xff0c;外部调试器和CPU之间的握手三&#xff0c;外部调试事件 External debug events1. External debug request event2. Halt instruction debug event3. Halting step debug…

是的,本科毕业八年,我考研了

今天&#xff0c;是一篇纯分享文。 是的&#xff0c;本科毕业八年&#xff0c;我考研了。 停更10个月&#xff0c;历时296天&#xff0c;我考研上岸了。 小伙伴们&#xff0c;好久不见。 一 发今年第一篇文章的时候刚处理完后续事宜&#xff0c;就简单说了句&#xff0c;后台…

Vue3 ts环境下的PropType

简介 在Typscript中&#xff0c;我们可以使用PropType进行类型的推断与验证。在日常的开发中我们常常会遇到下面这样的场景&#xff1a; 我们通过request请求从服务端获取了一条数据&#xff0c;数据是个Array的格式&#xff0c;Array中的每个元素又是一个对象&#xff0c;像下…

【神经网络与深度学习】循环神经网络基础

tokenization tokenization&#xff1a;分词 每一个词语都是token 分词方法&#xff1a;转为单个词、转为多个词语 N-gram表示法 准备词语特征的方法 &#xff08;把连续的N个词作为特征&#xff09; 如 ”我爱你“——>[我&#xff0c;爱&#xff0c;你] 2-gram——[[我…

java项目之校园兼职系统(ssm框架+mysql数据库+文档)

项目简介 校园兼职系统的主要使用者分为&#xff1a;管理员&#xff1a;首页、个人中心、专业管理、商家管理、热门兼职管理、学生管理、兼职接单管理、学生咨询管理、兼职任务管理、完成评价管理、管理员管理、系统管理等模块信息的查看及相应操作&#xff1b;学生&#xff1…

在vue中配置样式 max-width:100px时,发现和width:100px一样没有对应的递增到最大宽度的效果?怎么回事?怎么解决?

原因&#xff1a; 可能时vue的样式大部分和display相关&#xff0c;有很多的联系&#xff0c;导致不生效 解决&#xff1a; 对设置max-width样式的元素设置display:inline-block;属性&#xff0c;即可生效&#xff0c;实现随着子元素的扩展而扩展并增加固定到最大的宽度

使用 ASE 拼接分子

在部分应用场景下&#xff0c;我们需要对两个分子片段进行拼接&#xff0c;例如锂电电解液数据库 LiBE 然而&#xff0c;当前并没有合适的拼接方法。下面是一些已有方法的调研结果&#xff1a; 在 LiBE 论文的附录里&#xff0c;作者使用 pymatgen 进行分子拼接。 其思路是&…

分享2024高校专业建设思路及建设效果

广东泰迪智能科技股份有限公司成立于2013年&#xff0c;是一家专业从事大数据、人工智能等数据智能技术研发、咨询和培训的高科技企业&#xff0c;公司基于十余年的数据智能产业实践经验&#xff0c;构建“产、岗、课、赛、证、文”融通的特色应用型人才培养模式&#xff0c;助…

MQ:延迟队列

6.1场景&#xff1a; 1.定时发布文章 2.秒杀之后&#xff0c;给30分钟时间进行支付&#xff0c;如果30分钟后&#xff0c;没有支付&#xff0c;订单取消。 3.预约餐厅&#xff0c;提前半个小时发短信通知用户。 A -> 13:00 17:00 16:30 延迟时间&#xff1a; 7*30 * 60 *…

微信营销快捷回复和微信多开-微信UI自动化(.Net)

整理 | 小耕家的喵大仙 出品 | CSDN&#xff08;ID&#xff1a;lichao19897314&#xff09; Q Q | 978124155 关于项目背景和本软件的介绍 因为本人前期基于微信自动化这块编写了一些文章&#xff0c;所以最近想着将文章内容点合并后开发一款真正能帮助别人的软件&#xff0…

AI赋能档案开放审核:实战

关注我们 - 数字罗塞塔计划 - 为进一步推进档案开放审核工作提质增效&#xff0c;结合近几年的业务探索、研究及项目实践&#xff0c;形成了一套较为成熟、高效的AI辅助档案开放审核解决方案&#xff0c;即以“AI人工”的人机协同模式引领档案开放审机制创新&#xff0c;在档…

07.QT信号和槽-2

一、自定义信号和槽 在Qt中&#xff0c;允许⾃定义信号的发送⽅以及接收⽅&#xff0c;即可以⾃定义信号函数和槽函数。但是对于⾃定义的信号函数和槽函数有⼀定的书写规范。 1.基本语法 1.1 自定义信号 &#xff08;1&#xff09;⾃定义信号函数必须写到"signals"…