Typescript基础巩固(持续更新)

开始

官网手册

// 安装全局编译工具包
npm i -g typescript
// yarn global add typescript
// 查看版本
tsc -v
// 编译
tsc ".ts文件路径"

语法

自动类型推论,枚举,数组类型

// 自动类型推论
let age = 123 // let age:number = 123
// age = "122"
age = 234

// string 基本类型
let str:string = "ts"
console.log(str.length);

// vue 父子组件传参
/* 
props: {
    msg: {
        type: String // 包装类
    }
}
*/

// const 声明的变量是不可修改的,意味着从始至终都必须是3.14,所以ts将其当做一个类型来看,这种类型称为【字面量类型】
// 鼠标悬浮查看显示类型推断
let num1 = 3.14  // let num1: number
const num = 3.14 // const num: 3.14

// 字面量(固定的值:常量) : 10 20 "aa" [] {} /^1/

type position = 'top' | 'bottom' | 'left' | 'right'
function fn(value:position){
    console.log(value);
}

// fn('test') 报错
fn('bottom')

// 枚举: 如果不设置值,默认从0开始
enum position {
    top, // 0
    bottom, // 1
    left, // 2
    right, // 3
}

const fn = (value:position):void => {
    console.log(value);
}

fn(position.bottom)

// 设置值
enum position2 {
    top = "上",
    bottom = "下",
    left = "左",
    right = "右",
}

const fn2 = (value:position2):void => {
    console.log(value);
}

fn2(position2.bottom)

// 数组类型
// 声明数组
// 方式1
let numArr: number[] = [1,2,3]
let strArr: string[] = ['1','2','3']

// 方式2
let numArr2: Array<number> = [6,8,9]

联合类型 | ,类型别名Type,可选链?,非空断言!

可选链操作符(判断属性是否存在),前面有(即不为null/undefined)才会执行后面的函数
非空断言:百分百确定有值的时候用,强制性

// 联合类型: |
let value:number | null = 1
value = null
let valueArr: (number | string)[] = [1,2,'3']
// |优先级较低,需要()包裹提升优先级

// 类型别名【复用性】
type valueType = (number | string)[]
let valueArr2:valueType = [1,2,'3']
let valueArr3:valueType = [1,2,'3']

// or
type valueType2 = number | string
let valueArr6:valueType2[] = [1,2,'3']
let valueArr7:valueType2[] = [1,2,'3']

// 其他用法
type s = string
let str:s = '123'

type objType = {
    name: string
}

let obj:objType = {
    name: '123'
}

type objType2 = {
    name: string
    age?: number,
    gender?: string,
    // fn: (value: string) => void
    fn(value: string):void
}

let obj2:objType2 = {
    name: '123',
    fn(value){
        console.log(value)
    }
}

// 如报错:对象可能未定义
// obj2.name.concat("123")
// 传统
if(obj2.name){
    obj2.name.concat("123")
}
// &&
obj2.name && obj2.name.concat("123")
// 可选链操作符(判断属性是否存在),前面有(即不为null/undefined)才会执行后面的函数
obj2.gender?.concat("性别")
// 非空断言:百分百确定有值的时候用,强制性
obj2.name!.length

// 对象函数调用
obj2.fn("hello world!")

函数类型

// 函数声明
// function 函数名(参数1:类型,参数2:类型):返回值类型{函数体}
function add(a:number,b:number):number{
    return a+b
}
const result = add(1,2)
console.log(result);


// 函数表达式
const add2 = function(a:number,b:number):number{
    return a+b
}

// 箭头函数
const add3 = (a:number,b:number):number => {
    return a+b
}

// 函数的类型别名
// 类型别名通常是给箭头函数/函数表达式使用的,不会给函数声明使用
type addType = (a:number,b:number) => number

const add3Type: addType = (a,b) => {
    return a+b
}

const add2Type: addType = function(a,b){
    return a+b
}

// 如果不写return 默认返回 undefined,ts自动类型推断为void
// void 无返回值
const fn = (value:string):void => {
    console.log(value);
}
fn("hello world!")

// 必选参数不能再可选参数后
const paramsFn = (name:string,age?:number):void => {
    console.log(name,age);
}

paramsFn("xiao",18)
paramsFn("Li")

Function

  • 全局类型 Function 描述 JavaScript 中所有函数值上存在的诸如 bind、call、apply 等属性。
  • 它还具有特殊属性,即 Function 类型的值始终可以被调用;这些调用返回any
  • 如果您需要接受任意函数但不打算调用它,则类型 () => void 通常更安全
// 无类型函数调用,默认返回any-----不建议使用
function doSomething(f: Function) {
  return f(1, 2, 3);
}

console.log(doSomething((a:number,b:number,c:number) => {
  return a+b+c
})) // 6

void

  • void 表示不返回值的函数的返回值(函数无返回值)。
  • 每当函数没有任何 return 语句,或者没有从这些返回语句返回任何显式值时,它就是推断类型。
  • 不会查看你的返回值,如果存在的话。

在 JavaScript 中,不返回任何值的函数将隐式返回值 undefined 。但是, void 在 TypeScript 中不是 undefined 一回事。

// 推断的返回类型为 void
function noop() { // 等同于 function noop():void{...}
  return;
}
console.log(noop()) // undefined 

// 还有另一种特殊情况需要注意,当函数定义具有 void 返回类型时,该函数不得返回任何内容。
/*
// Type 'number' is not assignable to type 'void'. 类型“number”不可分配给类型“void”
function fn():void{
    return 22
}
console.log(fn())
*/

/*
// 执行错误
function f2(): void {
  // @ts-expect-error
  return true;
}
 
const f3 = function (): void {
  // @ts-expect-error
  return true;
};
 */

// -----------------
// 返回类型为 void 的上下文类型化不会强制函数不返回任何内容。换句话说,返回类型为 void 的上下文函数类型(type voidFunc = () => void)在实现时可以返回任何其他值,但会被忽略。
type voidFunc = () => void;
 
const f1: voidFunc = () => {
  return true;
};
 
const f2: voidFunc = () => true;
 
const f3: voidFunc = function () {
  return true;
};
// 当其中一个函数的返回值分配给另一个变量时,它将保留以下 void 类型
const v1 = f1(); // true 
console.log(v1)

const v2 = f2(); // true 
console.log(v2) 

const v3 = f3(); // true 
console.log(v3)

// 这种行为的存在使得即使 Array.prototype.push 返回一个数字并且 Array.prototype.forEach 方法需要一个返回类型为 void 的函数,以下代码也是有效的
const src = [1, 2, 3];
const dst = [0];
 
// 不会查看你的返回值,如果存在的话。
src.forEach((el) => dst.push(el));

function doSomething():number{
    return 22
}
function callMeMaybe(callback: () => void) {
	console.log(callback()) // 22 --- 这里期望一个 void,但 doSomething() 返回一个 number
    callback(); 
}
console.log(doSomething()) // 22
console.log(callMeMaybe(doSomething)) // undefined 


元祖、any

// 数组类型:可以限定类型,无法限制长度
let arr:number[] = [1,2,3]

// 元祖类型:限定数组的固定类型和数组长度
// 地图:经纬度
let arr2:[number,string] = [1,'2']

// any类型:不建议使用,会失去ts类型保护机制
let a:any = 1
a = '1'

unknown

未知类型代表任何值。这与 any 类型类似,但更安全,因为使用未知值执行任何操作都是不合法的

当从外部(如用户输入、第三方API响应)接收数据时,开始时可以将其标记为 unknown,然后逐步验证并转换为具体的类型
unknown 是TypeScript中一种更为保守和安全的类型,在处理不确定类型的数据时采取更为严谨的态度,从而减少潜在的运行时错误

类型谓词 is

类型谓词

注意:is不是ts语法中的关键字,而是一种惯例,通常用于命名用户自定义的类型守卫函数。
通常自定义类型守卫函数,可以在代码块中缩小变量的类型范围,以便更准确地推断变量的类型。

// 定义一个函数,其返回类型为类型谓词
type Fish = { swim: () => void };
type Bird = { fly: () => void };
// pet is Fish 是本例中的类型谓词。
// 谓词采用 parameterName is Type 的形式,其中 parameterName 必须是当前函数签名中的参数名称。
function isFish(pet: Fish | Bird): pet is Fish {
    return (pet as Fish).swim !== undefined;
}

// --------------------------

// 自定义类型守卫函数
function isString(value:any):value is string{
    // return '' // 不能将类型“string”分配给类型“boolean”
    return typeof value === 'string'
}

let example:any = "hello"
let count:any = 1

if(isString(example)){
    console.log("example类型被缩小为string");
}

if(isString(count)){
    console.log("不是string类型");
}

如何获取接口返回的未知数据?

使用类型守卫和断言

// 定义类型
interface ResType {
  code: number,
  msg: string,
  data: AddressType
}
interface AddressType {
  id: number,
  username: string,
  sex: number,
  address: string,
}

// 判断返回类型
function isResType(obj: unknown): obj is ResType{
  return typeof obj === 'object' && obj !== null &&
  ('code' in obj && typeof obj.code === 'number') &&
  ('msg' in obj && typeof obj.msg === 'string') &&
  ('data' in obj && isAddressType(obj.data))
}

// 判断地址类型
function isAddressType(obj: unknown): obj is AddressType{
  return typeof obj === 'object' && obj !== null &&
  ('id' in obj && typeof obj.id === 'number') &&
  ('sex' in obj && typeof obj.sex === 'number') &&
  ('username' in obj && typeof obj.username === 'string') &&
  ('address' in obj && typeof obj.address === 'string')
}

// 假设接口返回的数据
// 完全正确
const responseData = {
  code: 200,
  msg: '新增成功',
  data: {
    id: 1,
    username: '小丽',
    sex: 1,
    address: '测试地址'
  }
}

// 缺少对应数据
const responseData2 = {
  code: 200,
  msg: '新增成功',
}

const result = isResType(responseData) // true
const result2 = isResType(responseData2) // false
console.log('result',result,'result2',result2)
console.log(responseData.data)
// Property 'data' does not exist on type '{ code: number; msg: string; }'
console.log(responseData2.data) // undefined 

// 缺少对应数据
const responseData3 = {
  code: 200,
  msg: '新增成功',
  data: {
    id: 1,
    username: '小丽',
    sex: 1,
  }
}
const result3 = isResType(responseData3) 
console.log('result3',result3) // false
// Property 'address' does not exist on type '{ id: number; username: string; sex: number; }'.
console.log(responseData3.data.address) // undefined 

never

缩小范围时,您可以将联合选项减少到已经消除所有可能性并且一无所有。在这些情况下,TypeScript 将使用类型 never 来表示不应该存在的状态。

正确示例

interface Circle {
    kind: "circle";
    radius: number;
  }
   
  interface Square {
    kind: "square";
    sideLength: number;
  }
 
  type Shape = Circle | Square;

  // never 来表示不应该存在的状态。
  function getArea(shape: Shape) {
    switch (shape.kind) {
      case "circle":
        return Math.PI * shape.radius ** 2;
      case "square":
        return shape.sideLength ** 2;
      default:
        const _exhaustiveCheck: never = shape;
        return _exhaustiveCheck;
    }
  }

never 错误示例

interface Circle {
    kind: "circle";
    radius: number;
  }
   
  interface Square {
    kind: "square";
    sideLength: number;
  }
  // 向 Shape 联合添加新成员将导致 TypeScript 错误:
  interface Triangle {
    kind: "triangle";
    sideLength: number;
  }
  type Shape = Circle | Square | Triangle;

  // never 来表示不应该存在的状态。
  function getArea(shape: Shape) {
    switch (shape.kind) {
      case "circle":
        return Math.PI * shape.radius ** 2;
      case "square":
        return shape.sideLength ** 2;
      default:
        const _exhaustiveCheck: never = shape; // 不能将类型“Triangle”分配给类型“never”。
        return _exhaustiveCheck;
    }
  }

泛型

泛型是可以保证类型安全前提下,让函数等与多种类型一起工作,从而实现复用(常用语函数、接口、class中)
调用fn函数时来指定传入参数类型

/* 
function fn(val: string | number | boolean){
    return val
}
*/
// 泛型
// 期望:调用fn函数时来指定传入参数类型
// <T>     : 声明泛型
// val: T  : 使用泛型
function fn<T>(val: T){
    return val
}
// console.log(fn<number>(12));
// console.log(fn<string>("hello world!"));
// 简化写法:调用时可以不加<类型> ts会自动推断类型
const result = fn(12)
console.log(result); // 12
console.log(fn("hello world!"));

result.toFixed(2)


泛型-类型约束

默认情况下,泛型函数的类型变量Type可以代表多个类型,这就导致无法访问任何属性
解决:为泛型添加约束来收缩类型(缩窄类型的取值范围)

添加泛型约束收缩类型

  1. 指定更加具体的类型
  2. 添加约束
// 默认情况下,泛型函数的类型变量Type可以代表多个类型,这就导致无法访问任何属性
function fn<T>(val: T){
    // console.log(val.length); // 类型“T”上不存在属性“length”。
    return val
}
const result = fn(12)
console.log(result);
console.log(fn("hello world!"));

result.toFixed(2)

// 1、指定更加具体的类型
// 指定泛型类型的数组,val确定是一个数组,可以使用length属性
function fnArr<T>(val: T[]){
    console.log(val.length);
    return val
}

fnArr([1,2])
fnArr(['1','2','hello'])

// 2、添加约束
// 创建一个接口,通过extends关键字为泛型添加约束
interface Ilength {
    length: number
}

function fnLen<T extends Ilength>(val: T){
    console.log(val.length);
    return val
}

console.log(fnLen("hello world!"));
// console.log(fnLen(123)); // 类型“number”的参数不能赋给类型“Ilength”的参数。

// 多个泛型
// 返回值any类型,如何解决
function fnAll(obj: object,key: string){ // function fnAll(obj: object, key: string): any
    return obj[key]
}


// function fnAll1<O,K>(obj: O,key: K){
//     return obj[key] // 类型“K”无法用于索引类型“O”。(即:不知道obj对象中是否存储对应的属性)
// }

// fnAll1({name: 'Li'},'name')
// fnAll1({name: 'Li'},'age')
// fnAll1({name: 'Li',gender: '女'},'gender')

// 解决 keyof 
// K extends keyof O   ->   继承O所有key
function fnAll2<O,K extends keyof O>(obj: O,key: K){
    return obj[key] // 类型“K”无法用于索引类型“O”。(即:不知道obj对象中是否存储对应的属性)
}

fnAll2({name: 'Li'},'name')
// fnAll1({name: 'Li'},'age') // 类型“"age"”的参数不能赋给类型“"name"”的参数
fnAll2({name: 'Li',gender: '女'},'gender')

const person = {
    name: 'TT',
    age: 19
}
fnAll2(person,'age') // 会自动提示可选key

keyof 常规用法

type T = {
    name: string
    age: number
    gender?: number
}

let num: keyof T = 'age' // 即 let num:number

泛型接口

interface IPerson<T>{
    name?: string
    age: T
    hobby?: T[]
}

let obj:IPerson<number> = {
    age: 18
}

let obj2:IPerson<string> = {
    age: '18',
    hobby: ['1','3','2']
}

const arr1:number[] = [1,2]
// 泛型接口 interface Array<T>
const arr:Array<number> = [1,2]

Type Guards 类型守卫函数

  1. 类型守卫函数在编程中通常用于在特定条件下确定变量的类型。
  2. 在ts中,可以提供更精确的类型信息。

用来缩小类型范围

  1. 使用现有的 JavaScript 构造来处理缩小范围 ,有两种主要形式的类型守卫函数:typeof / instanceof
  2. 使用类型谓词 is

js运算符in

用于确定对象或其原型链是否具有具有名称的属性

type Fish = { swim: () => void };
type Bird = { fly: () => void };
type Human = { swim?: () => void; fly?: () => void };
 // 缩小类型范围
function move(animal: Fish | Bird | Human) {
  if ("swim" in animal) {
    animal; // (parameter) animal: Fish | Human
  } else {
    animal; // (parameter) animal: Bird | Human
  }
}

js运算符instanceof

用于检查一个值是否是另一个值的“实例”

function logValue(x: Date | string) {
    if (x instanceof Date) {
      console.log(x.toUTCString()); //   (parameter) x: Date
    } else {
      console.log(x.toUpperCase()); //   (parameter) x: string
    }
}

dom元素,ts关键字as(类型断言)

as用于类型断言,即开发者明确告诉ts某个值的类型。
在你清楚知道某个值的类型并想要覆盖ts的类型检查时很有用。

// dom元素类型
// 技巧
// 1、获取dom元素的ts类型: 浏览器控制台查看[[Prototype]]
// 2、const result = document.createElement("a") // const result: HTMLAnchorElement
const result = document.createElement("a") // 鼠标悬浮result查看显示类型推断

// 获取a标签类型
const a = document.getElementById('getLink') // 自动类型推断 HTMLElement | null
// 获取div标签类型
const div = document.getElementById('getDiv')

// 报错  类型推断不正确
// a && a.href // 类型“HTMLElement”上不存在属性“href”。

// 解决:类型断言as【自定义获取指定元素的结果类型】
const aAs = document.getElementById('getLink') as HTMLAnchorElement
console.log(aAs.href);

// HTMLElement是父,HTMLAnchorElement是子,层级关系

interface vs type

// interface vs type
// interface只能约束对象,type可以更灵活使用
// 推荐type写法

/* 
给对象约束属性和方法
基础语法
interface 接口名{
    属性名: 类型
} 
*/

interface Iobj {
    name: string
    age: number
    gender?: number
    fn: (value:string) => void
}

const obj:Iobj = {
    name: "Li",
    age: 18,
    fn(value){
        console.log(value)
    }
}

obj.fn("hello")

// 接口继承【Ison具备Iobj的所有约束规则】
interface Ison extends Iobj {
    score: number
    eat():void
}

// type实现继承效果
type objType = {
    name: string
    age: number
    gender?: number
    fn: (value:string) => void
}

// 继承 &与连接符:既要满足前面的也要满足后面的
type sonType = {
    score: number
    eat():void
} & objType


const obj2: Ison = {
    score: 100,
    eat(){
        console.log("eat!")
    },
    name: "Li",
    age: 18,
    fn(value){
        console.log(value)
    }
}

const obj3: sonType = {
    score: 100,
    eat(){
        console.log("eat!")
    },
    name: "Li",
    age: 18,
    fn(value){
        console.log(value)
    }
}

// type |或连接符:实现其中一种约束即可
type orType = {
    score: number
    eat():void
} | objType

const obj6: orType = {
    score: 100,
    name: "Li",
    age: 18,
    fn(value){
        console.log(value)
    }
}

函数重载

函数重载(Function Overloads)允许您为同一个函数提供多个函数签名,从而使得函数可以根据传入参数的不同类型执行不同的操作或返回不同类型的值。这提高了代码的灵活性和类型安全性。

  • 重载签名:定义了函数可以接受的参数类型和返回类型,但不包含函数体。(通常2个或更多)
  • 实现签名:实际的函数实现,它需要能够处理所有重载签名的情况。
function makeDate(a: number): number; // 重载签名1
function makeDate(a: number, b: number, c: number): number;  // 重载签名2
/*
在必需的参数之后编写了一个带有两个可选参数的函数,也不能用两个参数调用它
实现签名还必须与重载签名兼容
*/
function makeDate(a: number, b?: number, c?: number): number { // 实现签名
  if (b !== undefined && c !== undefined) {
    return a + b + c;
  } else {
    return a;
  }
}
const d1 = makeDate(12345678); // 重载签名1
const d2 = makeDate(5, 5, 5); // 重载签名2
// No overload expects 2 arguments, but overloads do exist that expect either 1 or 3 arguments.
// 没有重载需要 2 个参数,但确实存在需要 1 或 3 个参数的重载
const d3 = makeDate(1, 3); // 没有此重载,根据参数个数符合 重载签名1,即return a;
console.log(d1) // 12345678 
console.log(d2) // 15 
console.log(d3) // 1 

//-----------------------------

function fn(x: string): string;
// This overload signature is not compatible with its implementation signature.
// 此重载签名与其实现签名不兼容。
function fn(x: number): boolean;
// 函数返回值类型未定义
function fn(x: string | number) {
  return "oops";
}
// 解决
/*
function fn(x: string | number):string| boolean {
  return "oops";
}
*/

// ------------------------------

function fn(x: boolean): void;
// This overload signature is not compatible with its implementation signature.
// 此重载签名与其实现签名不兼容。
function fn(x: string): void;
function fn(x: boolean ) {
  return x
}
console.log(fn(true)) //ok
console.log("hello world") //"hello world" 
// 解决
// function fn(x: boolean | string) {}

ts类型声明文件

ts中有两种文件类型

  • .ts文件:包含类型信息以及执行代码,可被编译成.js文件,用于程序编写
  • .d.ts文件:只包含类型信息的类型声明文件,不会生成.js文件,用于提供类型信息

项目开发中写的.ts文件,上线时会打包成.js文件,丢失了类型。解决:需要额外准备一个类型声明文件(.d.ts)
在项目开发中使用的第三方库,会有对应的ts类型,如何实现的呢?类型声明文件(.d.ts)
如何为老项目的js库提供类型信息,使用.d.ts文件(类型声明文件)

类型声明文件

  1. 内置类型声明文件
  2. 第三方库类型声明文件(存在形式:1、库自带类型声明文件[axios];2、由definitelyType(github仓库)开源组织提供的,一般通过安装对应依赖npm i @type/xxx -D[jquery没有自带的类型声明文件,安装npm i @type/jquery -D])
// npm i axios
// 库自带类型声明文件
// 接口返回值类型
type ResType = {
    data: {
        list: {
            id: number
            name: string
            address: string
        }
    }
    message: string
    code: number
}
import axios from 'axios'
async function getApi(){
    const res = await axios.get<ResType>("api地址") // const res: AxiosResponse<any, any>
    console.log(res.data.code); // res.data之后就没有提示了,需要自定定义接口返回的属性类型
}

/**
 * 无法找到模块“jquery”的声明文件。“d:/study/vue3-ts/node_modules/jquery/dist/jquery.js”隐式拥有 "any" 类型。
 * 尝试使用 `npm i --save-dev @types/jquery` (如果存在),或者添加一个包含 `declare module 'jquery';` 的新声明(.d.ts)文件
 */
import $ from 'jquery'
// 没有提示
// 安装依赖 npm i @types/jquery -D 
$.ajax({
    method:'GET'
})

自定义类型声明文件–共享数据

  1. 创建.d.ts文件,并使用export导出
// 按需导出,提高性能
export type personType = {
    name: string
    age: number
}
  1. 使用Import导入(注意:.d.ts文件后缀不需要填写)
import type { personType } from './types/index'
let p: personType = {
  name: 'Zz',
  age: 18
}

为老项目添加类型声明文件

注意 .js和.d.ts文件名必须一致

home.js

// js文件,老项目
let count = 10
let str = "hello world"
let position = {
    top: 0,
    bottom: 10
}
function fn(val){
    console.log(val);
}

function fnArrow(a,b){
    return a+b
}

export {
    count,
    str,
    position,
    fn,
    fnArrow
}

home.d.ts

// declare let count:number // 文件“d:/study/vue3-ts/src/types/index.d.ts”不是模块。
export declare let count:number
export declare let str:string
export declare let position: {top: number,bottom: number}

enum position {
    top = "上",
    bottom = "下",
    left = "左",
    right = "右",
}
export declare function fn(params:position) :void

// export declare const fnArrow = (val:number) => number // 报错
type fnType = (a:number,b:number) => number
export declare const fnArrow:fnType

使用

index.ts

// 报错 文件“d:/study/vue3-ts/src/types/index.d.ts”不是模块。
// 解决: 创建home.d.ts类型声明文件
import { count,fnArrow,fn, position } from './home'
fn(position.bottom)
const result = fnArrow(count,20)
console.log(result )

vue

vscode

Vue Language Features (Volar)
TypeScript Vue Plugin (Volar):用于支持在 TS 中 import *.vue 文件。
Error Lens
vuejs官网组合 API 的 TypeScript
快速创建项目模版:vabtss or vab-ts-setup
建议根据官方文档学习,其他文档与官网内容会有出入。

基础

<template>
  <div class="-container">
    <div>使用ref: {{ obj.name }}</div>
    <div>使用reactive: {{ obj2.name }}</div>
    <div>使用computed: {{ computedLength }}</div>
    <button @click="btnClick">点击事件</button>
    <div>
      <img
        ref="myImg"
        src="https://copyright.bdstatic.com/vcg/creative/cc9c744cf9f7c864889c563cbdeddce6.jpg@h_1280"
        width="100"
        height="100"
      />
    </div>
    <div>
      <button @click="getImgRef">修改图片-null</button>
    </div>
  </div>
</template>
import { computed, reactive, ref } from 'vue'
defineOptions({
  name: 'BaseGrammar'
})
// --------------ref--------------------
// 为ref设置泛型
const str = ref<string>('hello world')
//   const obj = ref<{
//     name: string,
//     age?:number,
//     bol: boolean
//   }[]>([
//     {name: 'Li',bol:false},
//     {name: 'Z',bol:true,age: 18}
//   ])
type Person = {
  name: string
  age?: number
  bol: boolean
}

const list = ref<Person[]>([
  { name: 'Li', bol: false },
  { name: 'Z', bol: true, age: 18 }
])

let obj: Person = list.value[0]
obj.name = 'Tt'
console.log(obj.name)
// --------------reactive--------------------

// 建议使用ref定义变量,reactive更新数据时需要注意丢失响应式问题
const obj2 = reactive<Person>({ name: 'Li', bol: false })
// 直接修改
obj2.name = 'Zz' // 没有丢失

// --------------computed--------------------
// 计算属性:不需要特意指定类型,会自动类型推断
const computedLength = computed<number>(() => {
  return list.value.length
})
console.log(computedLength.value)

// --------------点击事件--------------------

// e默认参数,推断类型技巧
// 第二种在点击事件(写入$event),鼠标悬浮$event查看推断类型 <button @click="btnClick($event)">点击事件</button>
function btnClick(e: MouseEvent) {
  // 第一种:打印控制台,查看[[Prototype]]
  console.log(e) // PointerEvent -> MouseEvent
  console.log(e.pageX, e.pageY)
}

// --------------Dom Ref--------------------
// 查看类型
const img = document.createElement('img')
// 类型“never”上不存在属性src 解决:指定具体类型:HTMLImageElement
const myImg = ref<HTMLImageElement | null>(null) // 获取实例
console.log(myImg.value) // null

const getImgRef = () => {
  console.dir(myImg.value)
  if (myImg.value) {
    myImg.value.src = ''
  }
  // console.log(myImg.value && myImg.value.src);
  console.log('获取地址', myImg.value?.src) // “myImg.value”可能为 “null”。解决:可选链?

  // 非空断言(慎用):百分百确定的值才能使用
  console.log('获取地址', myImg.value!.src) // 解决:非空断言!
}

父子组件

1、可以使用基于类型的声明或运行时声明,但不能同时使用两者。

// 非ts语法
// 运行时声明
// const props = defineProps({
//   obj: { type: String, required: true, default: '默认值' }, // 无提示属性,自己打全
//   msg: String
// })
// props.msg

// ts语法
// 基于类型的声明: 通过泛型类型参数定义具有纯类型的 props 
type PropsType = {
    msg: string // 必传
    age?: number // 可选
    hobby?: string[]
}
// const props = defineProps<PropsType>()
// 注意解构不是响应式
// const { msg } = defineProps<PropsType>()
// 设置默认值
// const { msg = "默认值" } = defineProps<PropsType>()

// 当使用基于类型的声明时,我们失去了为 props 声明默认值的能力。这可以通过 withDefaults 编译器宏解决
const props = withDefaults(defineProps<PropsType>(), {
  msg: 'hello',
  age: 18,
  hobby: () => ['one', 'two']
})

// --------------------------------
// 非ts语法
// const emit = defineEmits(['btnChange', 'sendMed'])

// ts语法
// 对事件名和参数做约束

// 基于选项
// const emit = defineEmits({
//   sendMed: (val: number) => {
//     // 返回 `true` 或 `false`
//     // 表明验证通过或失败
//     return true
//   },
//   btnChange: (val: string) => {
//     // 返回 `true` 或 `false`
//     // 表明验证通过或失败
//     return true
//   }
// })

// 基于类型
// 语法:(e:事件名,参数1:类型,参数2:类型):void
//  const emit = defineEmits<{
//   (e: 'btnChange',val: string):void
//   (e: 'sendMed',val: number):void
//  }>()

// 3.3+: 可选的、更简洁的语法
const emit = defineEmits<{
  sendMed: [val: number]
  btnChange: [val: string]
}>()

const btnChange = () => {
  emit('btnChange', '子组件点击事件')
}

const sendMed = () => {
  emit('sendMed', 1)
}

报错集合

  1. 无法在“–isolatedModules”下编译“main.ts”,因为它视为全局脚本…
    不建议,按要求export
// 在tsconfig.json中的isolatedModules修改为false
{
  "compilerOptions": {
    "isolatedModules": false,
    }
  }
}
  1. 找不到模块“./xxx.vue”或其相应的类型声明。
    尝试: Vue Language Features (Volar)重启,或者vscode重新打开

【不好,存在any】

// 解决 配置 让ts认识.vue后缀的文件 默认没有 【有疑问】
// env.d.ts 声明文件扩充
declare module '*.vue' {
    import type { DefineComponent } from "vue"
    const component:DefineComponent<{},{},any>
    export default component
}
 	// 在tsconfig.json compilerOptions属性添加 
    "baseUrl": "./",// 解析非相对模块的基础地址,默认是当前目录
    "paths": {
    // 路径映射,相对于baseUrl
      "@/*":["src/*"]
    }
 // 在tsconfig.json include属性引入 'env.d.ts'
   "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue","env.d.ts"],
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值