TypeScript基本用法

本文介绍了如何在React项目中使用TypeScript,包括安装@types库以获得类型声明,以及如何定义数组、接口、枚举、函数、对象和泛型。还探讨了类型断言、联合类型、泛型约束和实用工具类型如Partial、Pick和Omit等,帮助提升代码的类型安全性和可维护性。
摘要由CSDN通过智能技术生成

在React中使用

使用 TypeScript 编写 React 代码,除了需要 TypeScript 这个库之外,还需要安装 @types/react@types/react-dom

npm i @types/react -s

npm i @types/react-dom -s

目前非常多的 JavaScript 库并没有提供自己关于 TypeScript 的声明文件

所以,ts 并不知道这些库的类型以及对应导出的内容,这里 @types 实际就是社区中的 DefinitelyTyped 库,定义了目前市面上绝大多数的 JavaScript 库的声明。

定义数组

需要注意的是,与javascript不同,在typescript中,数组中的每一项都必须是所定义了的类型;如果需要像javascript中一样使用可以传入不同类型的数组,考虑使用tuple

定义数组常用的表示法有:

  1. 类型+方括号
const HappyNums:number[]=[1,2,3,4,5]

在这里我们定义了number的数组,所以传入的必须都是number类型

  1. 数组泛型
let HappyNums:Array<number>=[1,2,3,4,5]

3.接口表示数组、类数组

function getNums(){
let args:{
[index:number]=number;
length:number
}=arguments
}

我们使用接口定义了args,实际上也可以采用原生的定义,,如 IArguments, NodeList, HTMLCollection

tuple元组

数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象

enum枚举

枚举(Enum)类型用于取值被限定在一定范围内的场景

enum Days {Sun, Mon, Tue, Wed, Thu, Fri, Sat};

定义函数

基本用法类似其余写法,注意:

  1. 会将添加了默认值的参数识别为可选参数
function buildName(firstName: string = 'Tom', lastName: string) {
    return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let cat = buildName(undefined, 'Cat');
  1. 使用…rest参数获取函数中的剩余参数

定义对象——接口

interface,在ts中用来定义对象的类型,有点类似js中class和实例的关系,不同的是,接口定义的是需要被约束的对象的类型,只理解概念不如来看代码

interface Student{
readonly id:number
name:string;
age:number;
graduated:false;
mood?:string
}

let Lili:Student={
name:'lili',
age:15,
graduated:false,
}

我们定义了一个名为Student的接口,同时让变量Lili的类型是Student,这样,Lili的类型就必须与Student规定的一致。

  • 可选属性:需要注意的是,我们在mood后添加了?,这说明这个属性是可选的,Lili可以有也可以没有。
  • 只读属性:希望某一属性只读,在变量前加上readonly——as const 使对象中每一个属性都为readonly

联合类型

联合类型(Union Types)表示取值可以为多种类型中的一种。

let myFavoriteNumber: string | number;
myFavoriteNumber = 'seven';
myFavoriteNumber = 7;
let myFavoriteNumber: string | number;
myFavoriteNumber = true;

// index.ts(2,1): error TS2322: Type 'boolean' is not assignable to type 'string | number'.
//   Type 'boolean' is not assignable to type 'number'.

联合类型使用 | 分隔每个类型。

这里的 let myFavoriteNumber: string | number 的含义是,允许 myFavoriteNumber 的类型是 string 或者 number,但是不能是其他类型。

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

联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型

类型断言

写法:

值 as 类型

用法:

  1. 联合类型中需要使用其中一个类型的方法时

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

interface Cat {
    name: string;
    run(): void;
}
interface Fish {
    name: string;
    swim(): void;
}

function isFish(animal: Cat | Fish) {
    if (typeof animal.swim === 'function') {
        return true;
    }
    return false;
}//这里会报错,因为swim是Fish的方法

我们可以使用类型断言小小地”欺骗“一下ts,这样就可以使用这个方法啦,具体的操作就是

interface Cat {
    name: string;
    run(): void;
}
interface Fish {
    name: string;
    swim(): void;
}

function isFish(animal: Cat | Fish) {
    if (typeof (animal as Fish).swim === 'function') {
        return true;
    }
    return false;
}//animal as Fish,ts会把animal认为是Fish,就可以使用其方法了

不过需要注意的是要确保你不会传入Cat类型的参数,不然代码在运行时依旧会报错

将父类断言为具体的子类——instanceof 与 as

当类之间有继承关系时,类型断言也是很常见的:

class ApiError extends Error {
    code: number = 0;
}
class HttpError extends Error {
    statusCode: number = 200;
}

function isApiError(error: Error) {
    if (typeof (error as ApiError).code === 'number') {
        return true;
    }
    return false;
}

上面的例子中,我们声明了函数 isApiError,它用来判断传入的参数是不是 ApiError 类型,为了实现这样一个函数,它的参数的类型肯定得是比较抽象的父类 Error,这样的话这个函数就能接受 Error 或它的子类作为参数了。

但是由于父类 Error 中没有 code 属性,故直接获取 error.code 会报错,需要使用类型断言获取 (error as ApiError).code

大家可能会注意到,在这个例子中有一个更合适的方式来判断是不是 ApiError,那就是使用 instanceof

class ApiError extends Error {
    code: number = 0;
}
class HttpError extends Error {
    statusCode: number = 200;
}

function isApiError(error: Error) {
    if (error instanceof ApiError) {
        return true;
    }
    return false;
}

上面的例子中,确实使用 instanceof 更加合适,因为 ApiError 是一个 JavaScript 的类,能够通过 instanceof 来判断 error 是否是它的实例。

但是有的情况下 ApiErrorHttpError 不是一个真正的类,而只是一个 TypeScript 的接口interface),接口是一个类型,不是一个真正的值,它在编译结果中会被删除,当然就无法使用 instanceof 来做运行时判断了:

interface ApiError extends Error {
    code: number;
}
interface HttpError extends Error {
    statusCode: number;
}

function isApiError(error: Error) {
    if (error instanceof ApiError) {
        return true;
    }
    return false;
}

// index.ts:9:26 - error TS2693: 'ApiError' only refers to a type, but is being used as a value here.

此时就只能用类型断言,通过判断是否存在 code 属性,来判断传入的参数是不是 ApiError

  1. 将any断言为具体类型/断言具体类型为any

前者用于解决历史遗留代码或是别的库存在的问题,后者建议用在百分百确定代码不会出错的情况来规避掉ts麻烦的报错

  1. as const 将属性变为readonly

Typescript 支持在类型声明后加上 as const,这样我们就相当于给每个属性添加 readonly

let t = {
 myProperty: "hi"
 myArr: [1, 2, 3]
} as const

现在,T 的所有属性值都是不可修改的。例如,t.myArr.push(1) 不能编译,给 myProperty 属性重新赋值同样也不能编译。

泛型

泛型指在定义的时候,不预先指定具体的类型,而是在使用的使用,才给变量指定类型,所以在定义的时候不会写出具体类型,而是用这样的形式表示:

我们这里定义了一个方法,为其传入length\value,表示创建一个为length长度的数组,并将该数组中的每一项都填充为value。我们希望数组中的每一项都是输入的value类型,所以我们可以给value设定一个泛型T,表示任意类型,后面的Array和value:T都是指的这个泛型,在传入的时候,只要确保他们的类型一致,就不会报错。

function createArray(length,value:T):Array<T>{
let res:T[]=[];
for(let i=0;i<length;i++){
    res[i]=value
}
return res

}

泛型约束

在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法:

function loggingIdentity<T>(arg: T): T {
  console.log(arg.length);
  return arg;
}

// index.ts(2,19): error TS2339: Property 'length' does not exist on type 'T'.

上例中,泛型 T 不一定包含属性 length,所以编译的时候报错了。

这时,我们可以对泛型进行约束,只允许这个函数传入那些包含 length 属性的变量。表现在代码上就是让泛型extends一个具有我们期待属性的接口:

interface Lengthwise{
length: number;

}

function loggingIdentity<T extends Lengthwise>(arg:T):T{
conse.log(arg.length);
return arg;

}

泛型接口

泛型除了可以用在函数中,也可以用在接口中,下面我们来实现一个泛型接口:

interface getItem<T>{
 (para:T):T
}

//使用时,在原本定义泛型的<T>传入参数的类型即可

const getBox:getItem<number>=para=>para

type

type person=string | number

使用场景:

  1. 字符串字面量: 取值只能是某几个字符串中的一个

type EventNames = 'click' | 'scroll' | 'mousemove';
function handleEvent(ele: Element, event: EventNames) {
    // do something
}
handleEvent(document.getElementById('hello'), 'scroll');  // 没问题
handleEvent(document.getElementById('world'), 'dblclick'); // 报错,event 不能为 'dblclick'
  1. 联合类型| 交叉类型& : 前者多选一,后者将类型合并为一个类型
  2. 类型别名:

类型别名会给一个类型起个新名字,类型别名有时和接口很像,但是可以作用于原始值、联合类型、元组以及其它任何你需要手写的类型

可以使用 type SomeName = someValidTypeAnnotation的语法来创建类型别名

type person=string | number

const NamePerson:person=string

utility type

Partial:将传入的类型设置为可选

function updateBook<T extends Book>(book: T, updates: Partial<T>) {
   const updatedBook = {...book, ...updates }
   notifyServer(updatedBook)
   return updatedBook
}
//原理:
type Partial<T> = {
  [P in keyof T]?: T[P];
}

**Pick**挑选一组属性并组成一个新的类型。

type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

Omit:删除可选类型

type Person={
name:string.
age:number,
isStudent:true,}

//使得lili可以没有age和isStudent属性,也可以不传入任何属性
const lili:Partial<Person>={name:'lili'}
//第一个参数:类型;第二个参数:要删除的类型
const jack:Omit<Person,'age'|'isStudent'>={name:'jack'}

Required从接口声明中移除具有 ? 属性的值。

interface T {
  maybeName?: string
}

type CertainT = Required<T> // 等价于 { maybeName: string }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值