typescript核心

类型注解

变量后面约定类型的语法,就是类型注解

作用: 约定类型,明确提示

// 类型注解

let age:number = 18;
age = 19;
// age = "hello";  //不能将类型“string”分配给类型“number”
  • :number 就是类型注解,为变量提供类型约束
  • 约定了什么类型,就只能给该变量赋值什么类型的值,否则报错
  • 并且,约定类型之后,代码的提示也会非常的清晰
原始类型

TS常用类型:

  • js已有类型
    • 简单类型:number , string , boolean , null ,undefined
    • 复杂类型 : 对象Object , 数组 Array ,函数Function
  • Ts新增类型
    • 联合类型 自定义类型(类型别名) , 接口 , 元组, 字面量类型 , 枚举 ,void , any , 泛型
数组类型
// 数组类型
// 第一种写法【推荐】
let numbers:number[] = [1,2,3];
// 第二种写法
let strings:Array = ["a","b","c"];
联合类型

将多个类型合并为一个类型

类型和类型之间使用 | 连接,代表类型可以是他们当中的其中一种,这种类型叫联合类型

// 数组中有number 和string 如何写?
let arr:(number | string |boolean)[] = [1,"hello",4,"456",true];

// 给定时器加类型

let timer:number | null = null; 
timer= setInterval(()=>{},1000)

类型别名

使用类型别名语法给类型重新起名字

当同一类型被多次使用时,可以通过类型别名,简化该类型的使用

// 类型别名
// let arr1:(number|string|boolean)[] =[1,2,"hello"];
// 类型别名   type 类型别名 = 具体类型

type CustomArr = (number | string | boolean)[];
let arr1:CustomArr = [1,2,"hello",true];
  • type 类型别名 = 具体类型 基本语法
  • 定义类型别名,遵循大驼峰命名规范,类似于变量
  • 使用类型别名,与类型注解的写法一样即可
函数类型

给函数指定类型,就是给 参数和返回值 指定类型

两种写法:

  • 在函数基础上 分别指定 参数和返回值类型
  • 使用类型别名 同时指定 参数和返回值的类型
// - 在函数基础上 **分别指定** 参数和返回值类型

// 函数声明
function add(num1:number,num2:number):number{
    return num1 + num2
}
console.log(add(1,2));

// 箭头函数
const add1 = (num1:number,num2:number):number=>{
    return num1 + num2;
}
console.log(add1(3,4))


// - 使用类型别名 **同时指定** 参数和返回值的类型   

//只适用于函数表达式
type AddFn = (num1:number ,num2:number) =>number

const add2:AddFn =(num1,num2)=>{
    return num1 + num2;
}

console.log(add2(7,8));
void类型

void函数返回值类型

如果函数没有返回值,定义函数类型时返回值类型为void

如果函数没有返回值,且没有定义函数返回值类型的时候,默认是void

// void类型
// 如果函数没有返回值,定义函数类型时返回值类型为void
const say = ():void=>{
    console.log("hi");
}
say()

// 如果函数没有返回值,且没有定义函数返回值类型的时候,默认是void
const say1 = ()=>{
    console.log("hhi");
}

say1()
  • 在js中如果没有返回值,默认返回的是undefined
  • 但是void 和undefined 在TypeScript中并不是一回事
  • 如果指定返回值类型是undefined 那返回值必须是undefined
// 如果指定返回值类型是undefined 那返回值必须是undefined
const add4 = ():undefined=>{
    return undefined;
}

使用 ? 将参数标记为可选

如果函数的参数,可以传也可以不传,这种情况就可以使用 可选参数 语法,参数后加 即可

const fn = (n?:number)=>{
    console.log(123)
}
fn();
fn(3);

案例

// 模拟slice函数, 定义函数参数类型
// 注意:必须参数不能位于可选参数后面
const mySlice = (start:number,end?:number) =>{
    console.log("起始index"+start+'结束index'+end)
}

mySlice(2)
mySlice(4,5)
对象类型

TS的对象类型,其实就是描述对象中的属性 方法的类型,因为对象是由属性和方法组成的

  • 声明对象结构 {}
  • 属性怎么写类型 属性名: 类型
  • 方法怎么写类型 方法名():返回值类型
// 空对象
let person:{} = {}

// 有属性的对象
let person1:{name:string} = {
    name:"zs"
}

// 有属性和方法,一行书写多个属性  ; 分割
let person2:{name:string;sayHi():void} = {
    name:"jack",
    sayHi(){}
}

// 换行写 可以省略 ; 符号
let person3 :{
    name:string
    sayHi():void
} = {
    name:"zs",
    sayHi(){}
}
扩展

对象类型中,函数使用箭头函数类型,属性设置可选,使用类型别名

  • 函数使用箭头函数类型

    let person5:{
       name:string
       sayHi:()=>void
    } = {
        name:"jack",
        sayHi(){}
    }
    
  • 对象属性设置可选

    // axiois({url,method}) 如果是get 请求method 可以省略
    const axios =(config:{url:string;method?:string})=>{}
    
  • 使用类型别名

    // { } 会降低代码可阅读性,建议对象使用类型别名
    
    type Config = {
        url:string;
        method?:string
    }
    
    const axios1 =(config:Config) =>{}
    
接口interface

使用interface声明对象类型

接口声明是命名对象类型的另一种方式

  • interface 后面是接口名称,和类型别名的意思一样
  • 指定接口名称作为变量的类型使用
  • 接口的每一行只能由一个属性或方法,每一行的分号可以省略
// 接口  interface声明对象类型

interface Person{
    name:string;
    age:number;
    sayHi:()=>void
}
// 使用类型
let person8:Person = {
    name:"zs",
    age:12,
    sayHi(){}
}
interface继承

使用extends实现接口继承,达到类型复用

语法:interface 接口A extends 接口B { }

继承后接口A拥有接口B的所有属性和函数的类型声明

// interface 继承
// 有两个接口,有相同的属性或函数,如何提高代码复用?
// interface Point2D {
//     x:number;
//     y:number;
// }
// interface Point3D {
//     x:number;
//     y:number;
//     z:number;
// }
// 继承  相同的属性或方法可以抽离出来,使用extends实现继承复用
interface Point2D {
    x:number;
    y:number;
}
// 继承Point2D
interface Point3D extends Point2D {
    z:number;
}
let p:Point3D ={
    x:12,
    y:23,
    z:56
}
type交叉类型

交叉类型实现接口的继承效果

使用 & 可以合并连接的对象类型 叫做交叉类型

// type交叉类型
// 使用type来定义Point2D 和Point3D
type Point2D = {
    x:number;
    y:number;
}

// 使用交叉类型 来实现接口继承的功能
type Point3D =Point2D & {
    z:number;
}

let o:Point3D= {
    x:1,
    y:2,
    z:3
}
interface vs type
  • 类型别名和接口非常相似,在很多情况下,可以在他们之间自由选择
  • 接口的几乎所有特性都以类型的形式可用,关键的区别在于不能重新打开类型以添加新属性,而接口总是可扩展的
interface type
支持:对象类型 支持:对象类型 其他类型
复用: 可以继承 复用: 交叉类型

不同点

  • type不可以重复定义
  • interface重复定义会合并
type Point2D = {
    x:number;
    y:number;
}
// 标识符“Point2D”重复
type Point2D = {
    age:number;
}

//-------------------------------------
interface Point2D {
    x:number;
    y:number;
}
//类型会合并  注意:属性类型和方法类型不能重复定义
interface Point2D {
   age:number
}
// 继承Point2D
interface Point3D extends Point2D {
    z:number;
}
let p:Point3D ={
    x:12,
    y:23,
    z:56,
    age:78
}

类型推断
  • TS中存在类型推断机制,在没有指定类型的情况下,TS也会给变量提供类型

开发项目时,能省略类型注解的地方就省略, 充分利用TS的类型推断能力,提高开发效率

// 发生类型推断的几个场景

// 变量a的类型被自动推断为 number
let a = 18;

// 函数的返回值类型被自动推断为 number
const add3 = (num1:number,num2:number) =>{
    return num1 + num2
}
字面量类型

js字面量如: 18 ‘jack’ [‘a’] {age:10} 等等

使用js字面量作为变量类型,这种类型就是字面量类型

// 'lucy' 是字面量类型
let n:'lucy' = 'lucy';
// 18 是字面量类型
let n1:18 = 18;
//   报错 不能将类型“19”分配给类型“18”
// n1 = 19;

let str1 = "hello";   //str1的类型是string
const str2 = "hello"; //str2的类型是 "hello"  str2是const声明的 值只能是 "hello"
字面量类型应用
// 性别只能是男 和 女  不会出现其他值
// let gender = '男';
// gender = '女' 
// 字面量类型 配合联合类型使用, 表示  一组明确的可选的值
type Gender = '男' | '女';
let gender:Gender = "男";
gender = "女"

type Direction = 'up' | 'down' | 'left' | 'right';


// direction的只能是 up ,down ,left ,right 中的任意一个
// 优点:使用字面量类型更加精确,严谨
function changeDirection(direction:Direction){
    console.log(direction)
}

changeDirection('left');
any类型

any类型的作用是逃避TS的类型检查

显示any: 当变量的类型指定为any的时候,不会有任何错误,也不会有代码提示,TS会忽略类型检查

隐式any:声明变量不给类型或初始值,函数参数不给类型或初始值

any的使用越多,程序可能出现的漏洞越多,因此【不推荐】使用any类型,尽量避免使用

// 显式any   
let obj:any = {age:18}
obj.bar = 100
// 不会报错  将来可能出现错误
obj = 23;

// 隐式any
let aa ;
const fn5 = (n4) =>{}

类型断言
  • 使用关键字 实现类型断言
  • 关键字as后面的类型是一个更加具体的类型(HTMLAnchorElement 是 HTMLElement的子类型)

有时候你会比ts更加明确一个值的类型,此时,可以使用类型断言来指定更具体的类型

// alink的类型 HTMlElement,该类型只包含a元素特有的属性或方法 
HTMLElement 使用这个类型 太宽泛 没包含a元素特有的属性或方法  href
const alink = document.getElementById('link')
<a id="link"></a>
我们很明确alink 获取到的就是一个a元素,通过类型断言,给它指定一个更具体的类型
const alink = document.getElementById('link') as HTMLAnchorElement
const img= document.getElementById('img') as HTMLImageElement
泛型

在ts中,泛型是一种创建可复用代码组件的工具,这种组件不只能被一种类型使用,而是能被多种类型复用类似于参数;

泛型是一种用于 增强类型(types)接口(interfaces)函数类型等能力的非常可靠的手段

泛型别名中使用泛型

泛型: 定义类型别名后 加上 <类型参数> 就是泛型语法,使用时传入具体的类型即可

是一个变量,可以随意命名,建议遵循大驼峰命名法

和类型别名配合,在类型别名后加上泛型语法,然后类型别名内就可以使用这个类型参数

泛型可以提高类型的复用性和灵活性

type User = {
    name:string;
    age:number
}

type Goods = {
    id:number;
    goodsName:string;
}

type Data = {
    msg:string;
    code:number;
    data:T
}

// 使用类型
type UserData = Data
type GoodsData = Data
泛型接口
  • 在接口名称的后面加上<类型参数>,那么这个接口就编程了泛型接口,接口中所有成员都可以使用类型参数
interface IdFn {
    id:()=>T;
    ids:()=>T[]
}

const idObj:IdFn = {
    id(){return 1},
    ids(){ return [1,2,3]}
}
内置的泛型接口
// 内置的泛型接口
const  arr7 = ["a","b"]
// Ts有类型推断能力  其实可以看作  const arr7:Array = [1,2,3]
const arr8:Array = [1,2,3]
// 通过Ctrl + 鼠标左键 去查看内置的泛型接口
arr7.push("7")
arr7.forEach(item=>(console.log(item)))
泛型函数
  • 函数名称后面加上,T是类型参数
  • 当我们调用函数的时候,传入具体的类型,T捕获这个类型,函数任意位置都可以使用该类型
  • 好处
    • 让函数可以支持不同类型(复用),保证类型是安全的
    • 调用函数,传入的数据可以推断出你想要的类型,就可以省略泛型
// 泛型函数
function getId(id:T):T{
    return id
}

let id1 = getId(1)
// TS会进行类型推断  参数的类型作为泛型的类型
let id2 =getId("2")

let id3 = getId({name:"zs"})

你可能感兴趣的:(vue3基础语法,typescript,前端,vue.js)