TypeScript解决了关于js类型检测的缺点
在前面我们提到过,TypeScript最终会被编译成JavaScript来运行,所以我们需要搭建对应的环境:
我们需要在电脑上安装TypeScript,这样就可以通过TypeScript的Compiler将其编译成JavaScript;
安装命令
npm install typescript -g
查看版本
tsc --version
如果我们每次为了查看TypeScript代码的运行效果,都通过经过两个步骤的话就太繁琐了:
第一步:通过tsc编译TypeScript到JavaScript代码;
第二步:在浏览器或者Node环境下运行JavaScript代码;
是否可以简化这样的步骤呢?
比如编写了TypeScript之后可以直接运行在浏览器上?
比如编写了TypeScript之后,直接通过node的命令来执行?
上面我提到的两种方式,可以通过两个解决方案来完成:
方式一:通过webpack,配置本地的TypeScript编译环境和开启一个本地服务,可以直接运行在浏览器上;
方式二:通过ts-node库,为TypeScript的运行提供执行环境;
安装ts-node
npm install ts-node -g
另外ts-node需要依赖 tslib 和 @types/node 两个包:
npm install tslib @types/node -g
现
在,我们可以直接通过 ts-node 来运行TypeScript的代码:
ts-node wyh.ts
声明了类型后TypeScript就会进行类型检测,声明的类型可以称之为类型注解;
在TypeScript定义变量(标识符)和ES6之后一致,可以使用var、let、const来定义。
var/let/const 标识符: 数据类型 = 赋值;
例如
数组的两种声明
let arr: string[] = ['11', '22', '33'];
let arr2:Array<number>=[1,2,3]
对象的声明
type info = {
name: string,
age:number
}
const obj:info = {
name: '123',
age:1
}
对于匿名函数我们一般不会添加类型,因为像foreach函数传入的匿名函数会自己进行类型推导,我们一般不用自己对于匿名函数的参数写类型,因为有可能写错。
js的基本数据类型ts都有,ts还有它独有的数据类型
any类型
在某些情况下,我们确实无法确定一个变量的类型,并且可能它会发生一些变化,这个时候我们可以使用any类型
我们可以对any类型的变量进行任何的操作,包括获取不存在的属性、方法;
我们给一个any类型的变量赋值任何的值,比如数字、字符串的值;相当于js
unknown类型
unknown是TypeScript中比较特殊的一种类型,它用于描述类型不确定的变量
void类型
void通常用来指定一个函数是没有返回值的,那么它的返回值就是void类型:
type FnType = () => void;
function a(fn: FnType) {
fn()
}
a(function () { console.log(1) })
当指定返回值类型是void类型时,我们返回东西也不会报错
never类型
never 表示永远不会发生值的类型,比如一个函数:
如果一个函数中是一个死循环或者抛出一个异常,那么这个函数会返回东西吗?
不会,那么写void类型或者其他类型作为返回值类型都不合适,我们就可以使用never类型;
tuple类型
tuple是元组类型,很多语言中也有这种数据类型,比如Python、Swift等。
它可以存放不同类型的元素
其次,元组中每个元素都有自己特性的类型,根据索引值获取到的值可以确定对应的类型;
//number
let number: number = 1;
console.log(number);
//布尔类型
let flag: boolean = true;
console.log(flag);
//string类型
let name1: string = 'wyh';
console.log(name1);
//array类型
let namearr: Array<string> = ['1', '2'];//不推荐
const namearr1: string[] = ['1', '2']//推荐
//object类型
const obj = {}
//null和undefined类型
const n1: null = null;
const u1: undefined = undefined;
//symbol类型
const s1: symbol = Symbol(1);
//any类型(类型可以改变)
let a1: any = 123;
a1 = '123';
console.log(a1);
//unknown类型(与any类型的区别是unknown类型只能赋值给any和unknown类型)
let aaa: unknown = 123;
let bbb:unknown
aaa = '1';
bbb = aaa;//只有bbb是any或者unknown类型才不报错
//void类型
//void通常用来指定一个函数是没有返回值的,那么它的返回值就是void类型:
//never类型
//元组类型
const arrs: [string, number, string] = ['1', 1, '2'];
//默认情况下可以推倒出标识符的类型时,不用加类型
let name2 = 'hhh';
let number1 = 123;
let flag1 = false;
函数的参数类型
function a(name: string) {
console.log(name);
}//参数的类型注解
// a(123)报错
a('wyh')
//函数的返回值类型
//我们也可以添加返回值的类型注解,这个注解出现在函数列表的后面:
function b(age: number, age2: number):number {
return age+age2
}
//参数为对象类型
function c(point: { x: number, y: number }) {
console.log(point.x,point.y);
}
c({ x: 10, y: 20 })
//可选类型
function d(point: { x: number, y: number, z?: number }) {
console.log(point.z);
}
d({ x: 1, y: 2, z: 3 })
d({ x: 1, y: 2 })
联合类型
//id是number或者string类型
function aa(id: number | string) {
//使用联合类型时需要小心,使用前需判断类型
//如果是字符串则将id转换为大写
if (typeof id === 'string') {
console.log(id.toUpperCase());
}
}
aa('abc')
类型别名
type Wyhtype = string | number;
function aaa(id: Wyhtype) {
console.log(aaa);
}
aaa(123)
type point = {
x: number,
y: number,
z?:number
}
如果你确定当前元素的类型,可以使用as来做类型断言,方便操作
例1:直接通过选择器获取的el假如是img元素,但是不做断言,使用el.src = ‘xxx’;会报错(断言成具体类型)
//类型断言,将el定义为img元素,as就是用于大范围转具体类型
var el = document.querySelector('wyh') as HTMLImageElement;
el.src = 'xxx';
function request(url: string, method: Method) {
}
例2:
断言成不太具体的类型,将number类型变为string类型
const age:number=111;
const age2 = age as any
const age3 = age2 as string
比如目前的情况,给一个可选属性赋值时会出错
解决方法一:
类型缩小
type Iperson = {
name: string,
friend?: {
age: string
}
}
const info: Iperson = {
name: '111'
}
if (info.friend?.age) {
info.friend.age = '222'
}
方法二:
非空类型断言
type Iperson = {
name: string,
friend?: {
age: string
}
}
const info: Iperson = {
name: '111'
}
info.friend!.age = '222'
type info = {
names: string,
age: number,
friend?: {
name:string
}
}
let info1: info = {
names: 'wyh',
age: 11,
friend: {
name:''
}
}
//可选链
//如果有friend那么就去,没有就是undefined,但不会报错
console.log(info1.friend?.name);
如下我们传入第二个参数报错,因为传第二个参数ts只能推导出是string类型,并不知到是Method类型
解决方法一:
使用类型断言
type Method = 'get' | 'post';
function request(url: string, method: Method) {
}
const info = {
name: 'xxx',
m: 'get'
}
request(info.name, info.m as Method)
方法二:
给info加类型
type Method = 'get' | 'post';
function request(url: string, method: Method) {
}
type Obj = {
name: string,
m: Method
}
const info: Obj = {
name: 'xxx',
m: 'get'
}
request(info.name, info.m)
类型别名可以用于其它类型 (联合类型、元组类型、基本类型(原始值)),interface不支持
type PartialPointX = { x: number };
type PartialPointY = { y: number };
// union(联合)
type PartialPoint = PartialPointX | PartialPointY;
// tuple(元祖)
type Data = [PartialPointX, PartialPointY];
//primitive(原始值)
type Name = Number;
// typeof的返回值
let div = document.createElement('div');
type B = typeof div;
interface 可以多次定义 并被视为合并所有声明成员 type 不支持
interface Point {
x: number;
}
interface Point {
y: number;
}
const point: Point = { x: 1, y: 2 };
函数声明表达式要写参数
//注意,参数的名字不能省略,比如type F = (number) => number;就是错的
type F = (num1: number) => number;
//fn的类型是F
const fn: F = function (num) {
return 1
}
//泛型:类型参数化
function sum<Type>(num1: Type, num2: Type): Type {
return num1
}
//让调用者以参数的形式告知函数的参数是什么类型
sum<number>(20, 30)
//当然我们也可以传入多个类型:
function foo<T, E>(arg1:T,arg2:E) {
return arg1
}
foo<number, string>(1, '2');
/*
平时在开发中我们可能会看到一些常用的名称:
T:Type的缩写,类型
K、V:key和value的缩写,键值对
E:Element的缩写,元素
O:Object的缩写,对象
*/
核心思想都是:把类型当一种特殊的参数传入进去
function fn<T>(arg: T): T {
return arg;
}
fn<number>(12);
interface Person<T1,T2>{
name: T1,
age:T2
}
//泛型接口
const p: Person<string, number> = {
name: 'wyh',
age:1
}
意义是规范函数的类型,那有人可能会问,直接标清参数的类型和返回的类型不就行了吗?
因为泛型可以传入类型,而标清类型的话只能适用于一种类型
我们无法确定一个变量的类型会使用,我们可以对any类型的变量进行任何的操作,包括获取不存在的属性、方法;我们给一个any类型的变量赋值任何的值,比如数字、字符串的值;相当于js
但是unknown不能获取不存在的属性,会直接报错,随意赋值不会报错
never代表永远不会发生值的类型
用于类型声明的文件,声明后可以直接在另外文件中使用,不需导入导出,但是不是说每个类型声明都要添加到这里面。
具体里面可以写type和declare
type.d.ts
type Ahc = {
name: string
}
declare const wyhname: string
declare是一般我们在文件a里声明了变量wyhname但是在b文件使用却报找不到的错误(比如在index.html中写了一个变量),我们可以在.d.ts中进行declare声明就可以用了
declare module '*.jpg'
上面代表将以.jpg结尾的文件声明为模块