目录

TypeScript 基础学习

TypeScript简介

  1. TypeScript由微软开发,基于JS的扩展语言
  2. TS包含了JS的所有内容,即TS是JS的超集
  3. TS增加了静态类型检查、接口,泛型等很多现代开发特性,因此适合大型项目的开发。
  4. TS需要编译为JS,然后交给浏览器或者其他JS运行环境执行。

为什么需要TS

今非昔比的JS

  • JS当年诞生的定位是浏览器的脚本语言,用于在网页中嵌入一些简单的逻辑,而且代码量很少,随着时间的推移,JS变得越来越流行,如今的JS已经可以全栈编程了。
  • 现如今的JS的应用场景比当年丰富的多,代码量也比当年大的多,随便一个JS项目的代码量,可以轻松的达到几万行,甚至十几万行。
  • 然而JS当年"出生简陋",没考虑到如今的应用场景和代码量,逐渐的就出现了很多困扰。

JS的困扰

不清不楚的数据类型

scss 复制代码
let welcome = 'hello'
welcome() // 此时报错 TypeError:welcome is not a function

有漏洞的逻辑

python 复制代码
const str = Date.now() % 2 ? '奇数''偶数'
if (str !== '奇数'){
    alert('hello')
}else if (str === '偶数'){
    alert('world')
}

访问不存在的属性

arduino 复制代码
const obj = {width:10,height:15}
const area = obj.width * obj.heigth // heigth 不存在,应该为height

低级的拼写错误

arduino 复制代码
const message = 'hello,world'
message.toUperCase() // toUperCase少写了一个p,应该是toUpperCase

【静态类型】检查

  • 在代码运行前进行检查,发现代码的错误或不合理之处,减小运行时异常的出现的几率,此种检查叫【静态类型检查】,TypeScript和核心就是【静态类型检查】,简言之就是把运行时的错误前置。
  • 同样的功能,TypeScript的代码量要大于JS,但由于TS的代码结构更加清晰,在后期代码的维护中TS却远胜于JS。

编译TypeScript

浏览器不能直接运行TypeScript代码,需要编译为JavaScript再交由浏览器解析器执行。

类型声明

typescript 复制代码
let a: String
let b: number
let c: boolean

a = 'hello'
b = -99
c = true

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

let result = count(1,2)
console.log(result)

类型推断

TS会根据我们的代码,进行类型推导,例如下面代码中的变量d,只能存储数字

ini 复制代码
let d =  -99 // TypeScript 会推断出变量的d的类型是数字
d = false // 警告:不能将类型'boolean'分配给类型'number'

但要注意,类型推断不是万能的,面对复杂类型时推断容易出问题,所以尽量还是明确的编写类型声明!

类型总揽

JS中的数据类型

string,number,boolean,null,undefined,bigint,symbol,object

其中object包含 Array,Function,Date,Error等。。。

TypeScript中的数据类型

  1. 上述所有的JavaScript类型
  2. 六个新类型 any,unknown,never,void,tuple,enum
  3. 两个用于自定义类型的方式 type,interface
typescript 复制代码
let str1: string // TS官方推荐的写法,只能值类型的字符串,不能写字符串形式的包装对象。
str1 = 'hello'
str1 = new String('hello')

let str2: String // 可以接受值类型的字符串,也能写字符串形式的包装对象。
str2 = 'hello'
str2 = new String('hello')

注意点⚠️

在JS中这些内置构造函数:Number、String、Boolean,它们用于创建对应的包装对象,在日常开发时很少使用,在TypeScript中也是同理,所以在TypeScript中进行类型声明时,通常都是写小写的number、string、boolean。

  1. 原始类型VS包装对象
  • 原始类型:如number、string、boolean,在JS中是简单数据类型,它们在内存中占用空间少,处理速度快
  • 包装对象:如Number对象,String对象,Boolean对象,是复杂类型,在内存中占用更多空间,在日常开发时很少由开发人员自己创造包装对象。
  1. 自动包装:JS在必要时会自动将原始类型包装成对象,以调用方法或访问属性。
javascript 复制代码
// 原始类型字符串
let str = 'hello'
//当访问str.length时,JS引擎做了一下工作:
let size = (function(){
    //1.自动装箱:创建一个临时的String对象包装原始字符串
    let tempStringObject = new String(str)
    
    //2.访问String对象的lenth属性
    let lengthValue = tempStringObject.length
    
    //3.销毁临时对象,返回长度值
    //(JS引擎自动处理对象销毁,开发者无感知)
    return lengthValue;
})

常用类型

any

any的含义是:任意类型,一旦将变量类型限制为any,那就意味着放弃了对改变量的类型检查

ini 复制代码
//明确的表示a的类型时any --- 【显式的any】
let a:any
//以下对a的赋值,均无警告
a = 100
a = '你好'
a = false

//没有明确的表示b的类型是any,但TS主动推断出来b是any -- 隐式的any
let b 
//以下对b的赋值,均无警告
b = 100
b = '你好'
b = false

注意点;any类型的变量,可以赋值给任意类型的变量

typescript 复制代码
/*注意点;any类型的变量,可以赋值给任意类型的变量*/
let c:any
c = 9

let x:string
x = c // 无警告 x = 9

unknown

unknown 的含义是:未知类型

  1. unknown可以理解为一个类型安全的any,适用于:不确定数据的具体类型
ini 复制代码
//设置a的类型unknown
let a:unknown

//以下对a的赋值,均正常
a = 100
a = false
a = '你好'

// 设置x的数据类型为string
let x:string
x = a // 警告:不能将类型'unknown'分配给类型'string'
  1. unknown会强制开发者在使用之前进行类型检查,从而提供更强的类型安全性
ini 复制代码
// 设置x的数据类型为string
let a:unknown
a = 'hello'

// 第一种
if(typeof a === 'string'){
    x = a
}

// 第二种(断言)
x = a as string

// 第三种方式:加断言
x = <string>a
  1. 读取any类型数据的任何属性都不会报错,而unknown正好与之相反
typescript 复制代码
let str1:string
str1 = 'hello'
str1.toUpperCase() // 无警告

let str2:any
str2 = 'hello'
str2.toUpperCase() // 无警告

let str3:unknown
str3 = 'hello'
str3.toUpperCase() // 警告,'str3'的类型为'未知'

// 使用断言强制指定str3的类型为string
(str3 as string).toUpperCase() // 无警告

never

never的含义是:任何值都不是,简言之就是不能有值,undefined、 null 、''、0 都不行

  1. 几乎不用never去直接限制变量,因为没有意义,例如:
ini 复制代码
//指定a的类型为never,那就意味着a以后不能存任何的数据了
let a:never

// 以下对a的所有赋值都会有警告
a = 1
a = true
a = undefined
a = null
  1. never一般是TypeScript主动推断出来的,例如
typescript 复制代码
// 指定a的类型为string
let a:string
// 给a设置一个值
a ='hello'

if (typeof a === 'string'){
    console.log(a.toUpperCase())
}else {
    console.log(a) // TS会推断出此处的a是never,因为没有任何一个值符合此处的逻辑
}
  1. never也可用于限制函数的返回值(一直调用循环,或者抛出异常的函数)
typescript 复制代码
//限制throwError函数不需要有任何返回值,任何值都不行,像undefined、null都不行
function throwError(str:string):never {
    throw new Error('程序异常退出:'+ str)
}

void

  1. void通常用于函数返回值声明,含义:【函数返回值为空,调用者也不应依赖其返回值进行任何操作】
c 复制代码
function logMessage(msg:string):void {
    console.log(msg)
}
logMessage('你好')

注意 :编码着没有编写return去指定函数的返回值,所以logMessage函数是没有显式返回值的,但是会有一个隐式返回值,就是undefined;即:虽然函数返回类型为void,但也是可以接受undefined的,简单记:undedined 是void可以接受的一种'空' 以下写法均符合规范

javascript 复制代码
//无警告
function logMessage(msg:string):void{
    console.log(msg)
}
//无警告
function logMessage(msg:string):void{
    console.log(msg)
    return;
}
//无警告
function logMessage(msg:string):void{
    console.log(msg)
    return undefined;
}

那限制函数返回值时,是不是undefined和void就没区别呢? --- 有区别,因为还有句话说:【返回值类型void的函数,调用者不应依赖其返回值进行任何操作!】对比下面两段代码:

c 复制代码
fuction logMessage(msg:string):void{
    console.log(msg)
}
let result = logMessage('你好')
if (result){ // 此行报错,无法测试'void'类型的表达式的真实性
    console.log('logMessage有返回值')
}
scss 复制代码
fuction logMessage(msg:string):undefined{
    console.log(msg)
}
let result = logMessage('你好')
if (result){ // 此行无警告
    console.log('logMessage有返回值')
}

理解void与undefined

  • void是一个广泛的概念,用来表达'空',而undefined则是这种'空'的具体实现之一。
  • 因此可以说undefined是void能接受"空"的状态的一种具体形式
  • 换句话说:void包含undefined,但void表达的语义超越了单纯的unedined,它是一种意图上的约定,而不仅仅是特定值的限制

总结:若函数返回类型为void,那么;

  1. 从语法上讲:函数是可以返回undefined的,至于显式返回,还是隐式返回,这无所谓!
  2. 从语义上讲:函数调用者不应关心函数返回的值,也不应依赖返回值进行任何操作!即使返回了undefined值。

object

关于object与Object,直接说结论;实际开发中用的相对较少,因为范围太大了。

object(小写)

object 小写的含义是:所有的非原始类型,可存储:对象、函数、数组等,由于限制的范围比较宽泛,在实际开发中使用的相对较少。

ini 复制代码
let a:object // a的值可以是任何【非原始类型】,包括,对象,函数,数组等

//以下代码,是将【非原始类型】赋给a,所以均符合要求
a = {}
a = {name:'张三'}
a = [1,3,5,7,9]
a = new String('123')
class Person{}
a = new Person()

// 以下代码,是将【原始类型】赋给a,有警告
a = 1 // 警告:不能将类型'number'分配给类型'object'
a = true // 警告:不能将类型'boolean'分配给类型'object'
a = '你好' // 警告:不能将类型'string'分配给类型'object'
a = null // 警告:不能将类型'null'分配给类型'object'
a = undefiend // 警告:不能将类型'undefined'分配给类型'object'

Object(大写)

  • 官方描述:所有可以调用Object方法的类型
  • 简单记忆:除了undefined和null的任何值
  • 由于限制的范围实在太大了!所以实际开发中使用频率极低
ini 复制代码
let a:Object // b能存储的类型是可以调用到Object方法的类型
b = {}
b = {name:'张三'}
b = [1,3,5,7,9]
b = new String('123')
class Person{}
b = new Person()
b = 1
b = true
b = '你好'

// 这两个是存不了的
// b = null
// b = undeinfed

声明对象类型

  1. 实际开发中,限制一般对象,通常使用以下形式
typescript 复制代码
//限制person1对象必须有name属性,age为可选属性
let person1:{name :string,age?:number}

// 含义同上,也能用分号做分割
let person1:{name :string;age?:number}

// 含义同上,也能用换行做分割
let person3:{
    name:string
    age?:number
}

//如下赋值均可以
person1 = {name:'李四',age:18}
person2 = {name:'张三'}
person3 = {name:'王五'}

// 如下赋值不合法,因为person3的类型限制中,没有对gender属性的说明
person4 = {name:'王五',gender:'男'}
  1. 索引签名:允许定义对象可以具有任意数量的属性,这些属性的类型可变的,常用于:描述类型不确定的属性(具有动态属性的对象)
typescript 复制代码
//限制person对象必须有name属性,可选age属性但值必须是数字,同时可以有任意数量、任意类型。
let person:{
    name:string,
    age?:number,
    [key:string]:any // 索引签名,完全可以不用key这个单词,换成其他的也可以。
}

//赋值合法
person = {
    name:'张三',
    age:18,
    gender:'男'
}

声明函数类型

typescript 复制代码
let count:(a:number,b:number) => number

count = function(x,y){
    return x + y
}

备注:

  • TypeScript中的 => 在函数类型声明时表示函数类型,描述其参数类型和返回类型
  • JavaScript中的 => 是一种定义函数的语法,是具体的函数实现
  • 函数类型还可以使用:接口、自定义类型等方式,下文中会详细讲解

声明数组类型

ini 复制代码
let arr1:string[]
let arr2:Array<string>

arr1 = ['a','b','c']
arr2 = ['hello','world']

备注:上述代码中的Array<string>属于泛型,下文会详细讲解

tuple

元祖(Tuple)是一种特殊的数组类型,可以存储固定数量的元素,并且每个元素的类型是已知的且可以不同。元祖用于精确描述一组值的类型, ?表示可选元素。

ini 复制代码
// 第一个元素必须是string类型,第二个元素必须是number类型
let arr1:[string,number]

//第一个元素必须是number类型,第二个元素是可选的,如果存在,必须是boolean类型
let arr2:[number,boolean?]

//第一个元素必须是number类型,后面的元素可以是任意数量的string类型
let arr3:[number,...string]

// 可以赋值
arr1 = ['hello',123]
arr2 = [100,false]
arr3 = [200]
arr3 = [100,'hello','world']
arr3 = [100] 

//不可以赋值,arr1声明时是两个元素,赋值的是三个
arr1 = ['hello',123,false]

enum

枚举(enum)可以定义一组命名常量,它能增强代码的可读性,也让代码更好维护

数字枚举

数字枚举一种最常见的枚举类型,其成员的值会自动递增,且数字枚举还具备反向映射的特点,在下面代码的打印中,不难发现:可以通过来获取对应的枚举成员名称

scss 复制代码
//定义一个描述【上下左右】方向的枚举Direction
enum Direction {
    Up,
    Down,
    Left,
    Right
}
cosole.log(Direction) // 打印Direction 会看到如下内容
/*
  0:'Up',
  1:'Down',
  2:'Left',
  3:'Right',
  Up:0,
  Down:1,
  Left:2,
  Right:3
*/

//反向映射
console.log(Direction.Up)
console.log(Direction[0])

//此行代码报错,枚举中的属性是只读的
Direction.Up = 'shang'

也可以指定枚举成员的初始值,其后的成员值会自动递增

scss 复制代码
enum Direction {
    Up = 6,
    Down,
    Left,
    Right
}
console.log(Direction.Up) // 6
console.log(Direction[1]) // 7

使用数字枚举完成刚才walk函数中的逻辑,此时我们发现:代码更加直观易读,而且类型安全,同时也更易于维护

scss 复制代码
enum Direction { 
    Up,
    Down,
    Left,
    Right
}

function walk(n:Direction){
    if (n === Direction.Up){
        console.log('向上走')
    }else if (n == Direction.Down){
       console.log('向下走')
    }else if (n == Direction.Left){
       console.log('向左走')
    }else if (n == Direction.Right){
       console.log('向右走')
    }
}
walk(Direction.Up)
walk(Direction.Down)

字符串枚举

ini 复制代码
enum Direction {
    Up = 'up',
    Down = 'down',
    Left = 'left',
    Right = 'right'
}
let dir:Direction = Direction.Up
console.log(dir) // 输出;'up'

常量枚举

官方描述:常量枚举是一种特殊枚举类型,它使用const 关键字定义,在编译时会被內联,避免生成额外的代码

type

type可以为任意类型创建别名,让代码更简洁、可读性更强,同时能更方便地进行类型复用和扩展。

1. 基本用法

类型别名使用type 关键字定义,type后跟类型名称,例如下面代码中 num 时类型别名

ini 复制代码
type num = number

let price:num
price = 100

2. 联合类型

联合类型是一种高级类型,它表示一个值可以是几种不同类型之一。

lua 复制代码
type Status = number | string
type Gender = '男''女'

function printStatus(status:Status){
    console.log(status)
}
function logGender(str:Gender){
    console.log(str)
}

3. 交叉类型

交叉类型(Intersection Types)允许将多个类型合并为一个类型,合并后的类型将拥有所有被合并类型的成员。交叉类型通常用于对象类型。

typescript 复制代码
type Area = {
    height:number; // 高
    width:number;// 宽
}

//地址
type Address = {
    num:number // 楼号
    cell:number // 单元号
    room:string // 房间号
}

type House = Area & Address

const house:House = {
    height:100, // 高
    width:100, // 宽
    num:3, // 楼号
    cell:4, // 单元号
    room:'702' // 房间号
}

属性修饰符

修饰符 含义 具体规则
public 公开的 可以被:类内部、子类、类外部访问
protected 受保护的 可以被:类内部、子类访问
private 私有的 可以被:类内部访问
readonly 只读属性 属性无法修改

public修饰符

typescript 复制代码
class Person {
    //name 写了public修饰符,age没写修饰符,最终都是public修饰符
    public name:string
    age:number
    constructor(name:string,age:number){
        this.name = name 
        this.age = age
    }
    speak(){
        //类的内部可以访问public修饰的name和age
        console.log('我叫:${this.name},今年${this.age}岁')
    }
}
const p1 = new Person('张三',18)
//类的【外部】可以访问public修饰的属性
console.log(p1.name)
scala 复制代码
class Student extends Person {
    constructor(name:string,age:number){
        super(name,age)
    }
    study(){
    // 【子类中】可以访问父类中的public修饰的:name属性,age属性
       console.log('今年${this.age}岁的${this.name}正在努力学习')
    }
}

属性的简写形式

简写前

typescript 复制代码
class Person {
    //name 写了public修饰符,age没写修饰符,最终都是public修饰符
    public name:string
    age:number
    constructor(name:string,age:number){
        this.name = name 
        this.age = age
    }
}

简写后

typescript 复制代码
class Person {
    constructor(public name:string,public age:number){}
}

protected修饰符

typescript 复制代码
class Person {
    constructor(protected name:string,protected age:number){}
    protected getDetails(){
        return `我叫:${this.name},今年${this.age}岁`
    }
    introduce(){
        console.log(this.getDetails())
    }
}
const p1 = new Person('张三',18)
p1.introduce() // public 可以在外部访问
// p1.name 在外部不能访问
// p1.getDetails 在外部不能访问
scala 复制代码
class Student extends Person {
    constructor(name:string,age:number){
        super(name,age)
    }
    study(){
       this.getDetails()
       console.log('${this.name}正在努力学习')
    }
}

const s1 = new Student('tom',1)
s1.study()

private修饰符

typescript 复制代码
class Person {
    constructor(name:string,age:number,privated IDCard;string){}
    private getPrivateInfo(){
        return `身份证号码为:${this.IDCard}`
    }
    getInfo(){
         return `我叫:${this.name},今年${this.age}岁`
    }
    getFullInfo(){
         return this.getInfo() + ',' + this.getPrivateInfo()
    }
}

readonly修饰符

typescript 复制代码
class Person {
    constructor(name:string,readonly age:number){}
}

抽象类

抽象类不能实例化可以被继承,抽象类里有普通方法,也可以有抽象方法

typescript 复制代码
abstract class Package {
    // 构造方法
    constructor(public weight:number){}
    // 抽象方法
    abstract calcuate():number
    //具体方法
    printPackage(){
        console.log('包裹重量为:${this.weight}kg,运费为:${
        this.calcuate()}元')
    }
}
scala 复制代码
class StandardPackage extends Package {
    constructor(weight:number,public unitPrice:number){super(weight)}
    calcuate():number {
        return this.weight * this.uniPrice
    }
}

const s1 = new StandardPackage(10,5)
s1.printPackage()
kotlin 复制代码
class ExpressPackage extends Package {
    constructor(weight:number,public unitPrice:number,public additional:number){super(weight)}
    calcuate():number {
        if (this.weight > 10){
            return 10 * this.uniPrice + (this.weight - 10) * this.uniPrice
        }else {
            return this.weight * this.uniPrice
        }
        
    }
}

const s1 = new ExpressPackage(13,8,2)
s1.printPackage()

总结:何时使用抽象类

  1. 定义通用接口:为一组相关的类定义通用的行为(方法或属性)时。
  2. 提供基础实现:在抽象类中提供某些方法或为其提供基础实现,这样派生类就可以继承这些实现。
  3. 确保关键字实现:强制派生类实现一些关键行为
  4. 共享代码和逻辑:当多个类需要共享部分代码时,抽象类可以避免代码重复。

interface 接口

interface 是一种定义结构的方式,主要作用是为:类、对象、函数等规定一种契约,这样可以确保代码的一致性和类型安全,但要注意interface只能定义格式不能包含任何实现

定义类结构

typescript 复制代码
// PersonInterface接口,用于限制Person类的格式
interface PersonInterface接口 {
    name:string
    age:number
    speak(n:number):void
}

// 定义一个类Person,实现PersonInterface接口
class Person implements PersonInterface {
    constructor(public name:string,public age:number){}
    //实现接口的speak方法,注意:实现speak时参数个数可以少于接口中的规定,但不能多
    speak(n:number):void {
        for (let i = 0;i < n ;i++) {
            //打印出包含名字和年龄的问候语句
            console.log(`我叫:${this.name},今年${this.age}岁`)
        }
    }
}

// 创建一个Person类的实例p1,传入名字'tom'和年龄18
const p1 = new Person('tom',18)
p1.speak(3)

定义对象结构

typescript 复制代码
interface UserInterface {
    name:string
    readonly gender:string // 只读属性
    age?:number // 可选属性
    run:(n:number) => void
}
const user:UserInterface = {
    name:'张三',
    gender:'男',
    age:18,
    run(n) {
        console.log('奔跑了${n}米')
    }
}

定义函数结构

typescript 复制代码
interface CountInterface {
    (a:number,b:number):number;
}
const count:CountInterface = (x,y) => {
    return x + y
}

接口之间的继承

一个interface 继承另一个interface,从而实现代码的复用

typescript 复制代码
interface PersonInterface {
    name:string // 姓名
    age:number // 年龄
}
interface StudentInterface extends PersonInterface {
    grade:string // 年级
}
const stu:StudentInterface = {
    name:'张三',
    age:17,
    grade:'高三'
}

接口自动合并(可重复定义)

typescript 复制代码
interface PersonInterface {
    name:string // 姓名
    age:number // 年龄
}
interface PersonInterface {
    grade:string // 年级
}

总结:何时使用接口?

  1. 定义对象的格式:描述数据模型,API响应格式、配置对象。。。等等你,是开发中用的最多的场景。
  2. 类的契约;规定一个类需要实现哪些属性和方法
  3. 自动合并:一般用于扩展第三方库的类型,这种特性在大型项目中可能用到。

一些相似概念的区别

interface 与 type 的区别

  • 相同点:interface 和 type 都可以用于定义对象结构,两者在许多场景中是可以互换的。
  • 不同点:
    1. interface:更关注于定义对象的结构,支持继承、合并
    2. type:可以定义类型别名、联合类型、交叉类型,但不支持继承和自动合并。

interface 和 type 都可以用于定义对象结构

typescript 复制代码
// 使用 interface 定义 Person对象
interface PersonInterface {
    name:string; // 姓名
    age:number; // 年龄
    speak():void;
}

// 使用type 定义 Person 对象
type PersonType = {
    name:string;
    age:number;
    speak():void;
}

let p1:PersonInterface = {
    name:'tom',
    age:18,
    speak(){
        cosole.log(this.name)
    }
}

interface 可以继承、合并

typescript 复制代码
interface PersonInterface {
    name:string // 姓名
    age:number // 年龄
}
interface PersonInterface {
    speak:() => void 
}

type 的交叉类型

interface 与抽象类的区别

  • 相同点:都用于定义一个类的格式(应该遵循的契约)
  • 不同点:
    1. interface:只能描述结构。不能有任何实现代码,一个类可以实现多个接口,用逗号','分隔。
    2. 抽象类:既可以包含抽象方法,也可以包含具体方法,一个类只能继承一个抽象类

泛型

泛型允许我们在定义函数、类或接口时,使用类型参数来表示未指定的类型,这些参数在具体使用时,才被指定具体的类型,泛型能让同一代码适用于多种类型,同时仍然保持类型的安全性

泛型函数

kotlin 复制代码
function logData<T>(data:T):T {
    console.log(data)
    return data
}
logData<number>(100)
logData<string>('hello')

泛型可以有多个

typescript 复制代码
function logData<T,U>(data:T,data2:U) : T | U {
    console.log(data1,data2)
    return Date.now() % 2 ? data1 :data2
}
logData<number,string>(100,'hello')
logData<string,boolean>('ok','false')

泛型接口

typescript 复制代码
interface PersonInterface<T> {
    name:string,
    age:number,
    extraInfo:T
}

let p1:PersonInterface<string>
let p2:PersonInterface<number>

p1 = {name:'张三',age:18,extraInfo:'一个好人'}
p2 = {name:'李四',age:18,extraInfo:250}

泛型约束

typescript 复制代码
interface PersonInterface<T> {
    name:string,
    age:number
}
function logPerson<T extends PersonInterface>(info:T):void {
     console.log(`我叫:${this.name},今年${this.age}
}

logPerson({name:'张三',age:18})

泛型类

csharp 复制代码
class Person<T> {
    constructor(
        public name:string,
        public age:number,
        public extraInfo:T,
    ){}
    speak(){
       console.log(`我叫:${this.name},今年${this.age}
       console.log(this.extraInfo)
    }
}
// 测试代码1
const p1 = new Person<number>('tom',30,250)

// 测试代码2
type JobInfo = {
    title:string,
    company:string
}
const p2 = new Person<JobInfo>('tom',30,{title:'研发总监',company:'xxxx科技公司'})

类型声明文件

类型声明文件是TypeScript中的一种特殊文件,通常以.d.ts作为扩展名,它的主要作用是为现有的JavaScript代码提供类型信息,使得TypeScript能够在使用这些JavaScript库或模块时进行类型检查和提示

demo.js

css 复制代码
export function add(a,b){ 
    return a + b
}
export function mul(a,b){
    return a * b
}

demo.d.ts

typescript 复制代码
declare function add(a:number,b:number):number;
declare function mul(a:number,b:number):number;
export {add,mul}
本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
天天扭码11 分钟前
ES6 Symbol 超详细教程:为什么它是避免对象属性冲突的终极方案?
前端·javascript·面试
小矮马15 分钟前
React-组件和props
前端·javascript·react.js
懒羊羊我小弟18 分钟前
React Router v7 从入门到精通指南
前端·react.js·前端框架
DC...1 小时前
vue滑块组件设计与实现
前端·javascript·vue.js
Mars狐狸1 小时前
AI项目改用服务端组件实现对话?包体积减小50%!
前端·react.js
H5开发新纪元1 小时前
Vite 项目打包分析完整指南:从配置到优化
前端·vue.js
嘻嘻嘻嘻嘻嘻ys1 小时前
《Vue 3.3响应式革新与TypeScript高效开发实战指南》
前端·后端
恋猫de小郭1 小时前
腾讯 Kuikly 正式开源,了解一下这个基于 Kotlin 的全平台框架
android·前端·ios
2301_799404911 小时前
如何修改npm的全局安装路径?
前端·npm·node.js
(❁´◡双辞`❁)*✲゚*2 小时前
node入门和npm
前端·npm·node.js