- 常规安装运行
npm i typescript -g
安装tsc -v
查看当前 typescript 版本- tsc -init 初始化项目
- tsc -w 编译成js
- 1.先运行 ts文件 将ts 文件进行编译 得到 js 文件
tsc ts文件
- 2.执行 js 文件
node js文件
- 简化运行
- npm i -g ts-node 简化运行
ts-node
文件名 运行
- 为变量添加类型约束
- 约定了是什么类型,就只能给变量 赋值该类型的值,否则会报错 (约定类型 写小写 大写用于接口)
let str:string='必须是字符串'
let srt = "1";
//不指定类型 会根据初始赋值来推导出变量的类型 以后str的类型不能改变const num = 1;
// 常量不能改变指向(不能被修改),所以它的值 就是它的类型
- 基础类型 number string boolean null undefined Symbol
- 对象类型 object array function
- TS 新增类型
- 联合类型、交叉类型 、 自定义类型(类型别名) 、接口 、元组 、字面量类型 、枚举 、void 、any
let strings: string = "最好的";
let numbers: number = 2019;
let booleans: boolean = true;
let undefineds: undefined = undefined;
let nulls: null = null;
let symbols: symbol = Symbol("唯一的");
- object 不包含基础数据类型 (例如string、number 等)
- Object 包含基础数据类型 (注意区分 object 首字母大小写)
- {}===Object
// object 不包含基础数据类型 let obj: object = { a: 1 }; let arr: object = [1]; // Object 包含基础数据类型 let obj2: Object = { a: 1 }; let arr2: Object = [1]; let string1: Object = "张三"; let number1: Object = 123; let boolean1: Object = true; // {} 等同于 Object let obj3: {} = { a: 1 }; let arr3: {} = [1]; let string2: {} = "张三"; let number2: {} = 123; let boolean2: {} = true;
- array 数组两种写法
- 1.
let a:Number[]=[1,2,3,4]
在类型约束后 添加中括号 表示 数组中的子级只能是当前约束类型 (推荐使用) - 2.
let b:Array<String> = ['a','b','c']
先约束为数组类型 在约束子级的类型,泛型 类型参数化(不推荐使用)
- 1.
&
用于组合多个类型为一个类型 (类似于接口继承 extends)- demo
interface person1 { name: string } interface person2 { age: number } type person3 = person1 & person2 let p: person3 = { name: '张三', age: 18 } // 表示 所有指定的类型都要存在 缺一不可 (age 为指定的常量) let obj: { name: string; age: 18 } & { sex: string }; obj = { name: "张三", age: 18, sex: "男" };
- 交叉类型和接口继承类型的不同点
- 相同点:都可以实现对象类型的组合
- 不同点:对于同名属性之间 处理类型冲突的方式不同
|
使用|(竖线) 由两个或多个其他类型组成的类型 表示可以是这些类型中的任意一种let a:(Number|String|Boolean)[]=[1,'string',true,234]
可以是联合类型中的任意类型
// 为 数字 或 字符串
let numAndsrt: number | string = 10;
// 为 数字 或 等于 "小八嘎"
let numAndsrt2: number | "小八嘎" = "小八嘎";
// obj 为 { a: 1 } 或者 { b: 2 } 也可以同时为 { a: 1, b: 2 }
let obj: { a: 1 } | { b: 2 } = { a: 1 };
obj = { a: 1, b: 2 };
- 当类型为any 时 可以对该值进行任意操作 并且不会有代码提示
- 最多临时使用any来代替复杂类型 后面进行更正
let names:any='张三'; names=123;
使用any类型后 失去ts类型保护
let msg: any = 1;
msg = "小八嘎";
msg = true;
// msg.toFixed(2) //使用当前数据类型不具有的方法 不会 提示报错
let msg2: unknown = 1;
msg2 = "小八嘎";
msg2 = true;
// msg2.toFixed(2); //使用当前数据类型不具有的方法 会 提示报错
- 使用 interface 声明创建 创建后使用接口名称作为变量的类型
- 当一个对象类型被多次使用时 使用接口 interface 来描述对象的类型 达到复用的目的
- demo
// 对象 interface ObjIft { // 属性名:值的类型 name: string; age: number; sex: string; } let obj: ObjIft; obj = { name: "张三", age: 18, sex: "男", }; // 数组 interface ArrIft { // [idx: number] 下标类型: 值类型; [idx: number]: number | string; } let arr: ArrIft; arr = [1, "2", 3]; // 函数 interface FnItf { // (形参及类型):返回值类型 (value1: string, value2: number): void; } let Fn: FnItf = (value1: string, value2: number) => {}; Fn("小八嘎", 27); //如下待处理 interface PersonS{ name: string; age: number; sayHi(abc: string): void; other: () => void } et person1: PersonS = { name:'张三', age:18, sayHi(i){ console.log('类型一',i); }, other() { console.log('类型二'); } } erson1.sayHi('参数')
- 将公共的属性和方法抽离出来 通过继承来实现复用
interface person1 { name: string; age:number} interface person2 extends person1{sex:string} let person: person2 = { sex: "男", name: "张三", age: 18 } interface NameIft { name: string; } // 继承 extends interface Ageift { age: number; } interface PersonIft extends NameIft, Ageift { sex: string; } let person: PersonIft; person = { name: "张三", age: 18, sex: "", };
// 同名
// 接口可以同名 定义参数类型会合并 但类型不同会报错
interface withItf {
name: string;
}
interface withItf {
age: number;
}
let withs: withItf = {
name: "张三",
age: 18,
};
// 缺省 xxx? : 类型 表示可以缺省这个属性 定义数据时可以不写
interface lack {
name: string;
}
interface lack {
age?: number;
}
let lacks: lack = {
name: "张三",
};
// 只读
interface readOnlys {
readonly numbers: number;
}
let rdy: readOnlys = { numbers: 10 };
// rdy.numbers = 11; //报错 不能修改为只读的属性
- 使用 type 关键字来创建类型别名 创建后直接使用该类型别名作为变量名的类型注解
- demo
//场景 当 如下约束出现多次时 每次都要单独设置 约束的集合 let a:(Number|String|Boolean)[]=[1,'string',true,234] //简化 type Arrays=(Number|String|Boolean)[] let array1:Arrays=[1,'string',true,234] let array2:Arrays=[234,'string',1,true] type AA = number | string let abc: AA = 123 abc = 'aaa' <!-- ---- --> // 自定义一个类型 type strAndnum = string | number; let sn: strAndnum = "字符串或者数字"; // 自定义一个对象类型 type objType = { name: string; age: number & 2 }; let obj: objType = { name: "张三", age: 2, };
-
函数的类型实际上指的是 函数参数和返回值的类型
-
1.单独指定参数和返回值的类型
//函数声明试 方式 function add(num1:number,num2:number):number{ return num1+num2 } let a=add(5,6) console.log(a); //11 //函数表达式 方式 const add=(num1:number,num2:number):number=>{ return num1+num2 } let a=add(5,6) console.log(a); //11
-
2.同时指定参数和返回值的类型 ```ts // 只适用于 函数表达式 方式 const add=(num1:number,num2:number):number=>(num1,num2)=>{ return num1+num2 } let a=add(5,6) console.log(a); //11
// 接口形式 interface FnItf { (p: string): number; } let fn: FnItf = (p: string) => { return 1; }; fn(""); // 自定义别名类型 形式 type FnType = (p: string) => void; let fn2 = (p: string): void => {}; fn2(""); ```
-
函数参数
// 函数参数的写法 // 不写为默认值 function test1(a: number, b: number = 3) { console.log(a, b); } test1(1); // 可以不写 function test2(a: number, b?: number) { console.log(a, b); } test2(1); // 结构剩余参数 function test3(a: number, b: number, ...arr: number[]) { console.log(a, b, arr); } test3(1, 2, 3, 4, 5);
-
void 当函数没有返回值 函数的返回值类型就是 void
function a(){} === function a():void{}
类型为 voidfunction str(name:string):void{console.log('单纯打印没有返回值') }
-
可选参数
- 可选参数 :在参数名后添加
?
表示可传可不传 - 可选参数 只能出现在参数列表的最后面 可选参数后 决定不能出现 必选参数
- demo
const add=(num1?:number,num2?:number):void=>{ console.log(`数字一:${num1}数字二:${num2}`); } add() //数字一:undefined数字二:undefined add(123) //字一:123数字二:undefined add(123,456) //数字一:123数字二:456
- 可选参数 :在参数名后添加
-
对象类型
- TS中对象类型就是在描述对象的结构 (有什么类型的属性和方法)
- demo
let person: { name: string; age: number; sayHi(abc: string): void; other:()=>void}={ name:'张三', age:18, sayHi(i){ console.log('类型一',i); }, other() { console.log('类型二'); } } person.sayHi('参数')
- 对象可选属性 (可选属性同函数可选参数 )
- demo
function myAxios(config:{url:string;method?:string}){} myAxios({ url:'123456' })
- demo
-
元组 (tuple)
- 元组类型是另一种类型的数组
- 使用场景: 当明确的知道包含多少个元素 以及特定索引对应的类型
- 元组类型可以确切的标记出有多少个元素 以及每个元素的类型
let person: [string, number, string] = ['张三', 18,'男']
- 不能多不能少 类型必须一一对应
-
类型推论
-
- 声明变量初始化时
let str='是字符串'
声明变量并立即初始化值 才可以进行省略 写类型let a; a = 18; a='789';
进行声明后 没有立即初始化值 不可以省略 导致ts无法确切规定类型
-
- 决定函数返回值时
- demo
function add(num1:number,num2:number):number{ return num1+num2 } //省略后 function add(num1:number,num2:number){ return num1+num2 }
-
-
类型断言 as
- 使用 as 关键字 实现类型断言
- 关键字as 后面的类型 是一个更加具体的类型
- demo
//,没使用as 进行类型断言 //getElementById方法返回的值类型是 HTMLelement 该类型不包含a标签特有的 href 等属性 //这个类型太宽泛 不具体 无法操作 href 等 标签特有的属性或方法 //使用 as 类型断言 指定更加具体的类型 let AA = document.getElementById('baidu') console.log(AA.href); let AA = document.getElementById('baidu') as HTMLAnchorElement console.log(AA.href); AA.onclick = (() => { console.log(1); })
-
字面量类型
- 场景 字面量类型配合类型一起使用 用来表示一组明确的可选值列表
- demo
let str1='hello ts' // let str1: string const str2='hello ts'//const str2: "hello ts" 等同于 const str3:'hello ts'='hello ts' //直接规定 类型对应的值 let age:19=10//error:不能将类型“10”分配给类型“19” let age2:19=19 function aa(direction: 'up' | 'down' | 'left' | 'right') { } aa('up')
-
typeof 操作符
- TS中的typeof 可以在类型上下文中引用变量或属性的类型 (或类型查询)
- 可以用于 根据已有变量的值 获取该值的类型 来简化类型书写
- typeof 只能用来查询变量或属性的类型 无法查询其他形式的类型 (例如函数调用的类型)
- demo
let person = { name: '张三', age: 18 } // function onePerson(point: { name: string; age:number}){} // 使用typeof function onePerson(point: typeof person){} onePerson({ name: "李四",age:19})
-(不赋值的情况下) 枚举成员的值 默认为 从0 开始自增
- 当给 一个枚举对象 赋值为数字 后面的枚举对象如果没值 依然会自动递增
- 字符串枚举没有自增长行为 因此每个字符串枚举成员 必须有初始值
- 字符串如果不是最后一个 那么必须全部有初始值
- demo
enum Direction{ up, down, left, right }
function changeDirection(direction: Direction) {
console.log(Direction.down);
}
// 自动递增
enum Direction{
up=10,//10
down, //11
left, //12
right //13
}
//枚举对象为 字符串时
enum Direction{
up,
down,
left,
right='a'
}
// 枚举 不是用来定义类型的 用于列举数据用的
enum StatusCode {
success = 200,
paramsError = 400,
serverError = 500,
}
let code: string | number = 200;
if (code === StatusCode.success) {
console.log("成功");
} else if (code === StatusCode.paramsError) {
console.log("失败,请求参数问题");
} else if (code === StatusCode.serverError) {
console.log("失败, 服务器问题");
}
enum StatusCode2 {
success,
paramsError = 400,
serverError,
}
console.log(
StatusCode2.success,
StatusCode2.paramsError,
StatusCode2.serverError
);
// 输出结果:0 400 401
// 会自动递增
-
TS中的class 不仅提供了 class 的语法功能 也作为一种类型存在
-
构造函数
- 成员初始化后 才可以通过this.xxx 来访问实例成员
- 需要为构造函数指定类型注解 否则会被隐式推断为 any
- 构造函数不需要返回值类型
- demo
class person { age: number name:string constructor(age: number, name: string) { this.age = age this.name=name } } const p=new person(18,'张三') console.log(p.name,p.age); //张三 18
//------------- class Person { // 定义属性前 应该先声明这个属性的类型,也可以同时设置默认值 myName: string = "默认值"; constructor(n: string) { this.myName = n; } getName() { return this.myName; } } let p = new Person("张三"); console.log(p.myName); console.log(p.getName);
// 创建一个类 ts 会自动生成一个对应的接口 interface
// 以上 class Person 相当于 如下 Person 接口 /* interface Person { myName: string; getName: () => string; } */
// 使用class Person 自动生成的接口 let obj: Person = { myName: "李四", getName() { return "abc"; }, };
-
继承 -方式1 extends 继承父类
- demo
class person1 { jineng1(){console.log('我会唱歌我会跳舞'); } } class person2 extends person1{ jineng2(){console.log('你放屁'); } } const AA = new person2() AA.jineng1() AA.jineng2()
-方式2 implements 实现接口 js中只有extend implements是TS的
- 通过 implements 关键字并配合 interface 让class 实现接口
- demo
interface person1 { jineng1(): void name:string } class person2 implements person1{ jineng1(){console.log('我是一个粉刷匠'); } name='张三' } const AA = new person2() AA.jineng1() console.log(AA.name);
- demo
-
类成员可见性
- public 公有的 公有成员可以被任何地方访问 (默认为可见可以省略)
- protected 受保护的 仅对齐声明所在类和子类中(非实例对象)可见
- private 私有的 只能在当前类中可见 对实例对象以及子类不可见
- demo
class person1 { public jineng1() { console.log('我会唱歌'); } protected jineng2() { console.log('我会跳舞'); } private jineng3() { console.log('你牛逼'); } } class person2 extends person1{ jineng4() { console.log('你放屁'); this.jineng2() } } const AA = new person2() AA.jineng1() // AA.jineng2() //属性“jineng2”受保护,只能在类“person1”及其子类中访问。 // AA.jineng3() //属性“jineng3”为私有属性,只能在类“person1”中访问
- demo
- readonly 只读
- 用于防止在构造函数之外对属性进行赋值
- 只能修饰属性 不能修饰方法
- 接口 或者{} 表示的对象类型 也可以使用 readonly
- 只要是 readonly 修饰的属性 必须手动提供明确的类型
- demo
class preson{ readonly age: number = 18 constructor(age: number) { this.age = age this.age=19 } } const p = new preson(20) console.log(p); // p.age=30 //error 无法分配到 "age" ,因为它是只读属性
-
static 静态属性(成员)
- 访问修改 只能通过类去操作
- 泛型是可以在保证类型安全前提下,让函数等与多种类型一起工作,从而实现复用,常用于:函数、接口、class中。
- 泛型在保证类型安全(不丢失类型信息)的同时,可以让函数等与多种不同的类型一起工作,灵活可复用
- 简化调用泛型函数 在调用泛型函数时 可以省略 <类型>
- demo
//需求:创建一个val 函数,传入什么数据就返回该数据本身(也就是说,参数和返回值类型相同) function val<T>(value: T): T { return value } const v = val<number>(123) //指定类型 并传入指定数据 //进行简化 const v = val(123) //指定类型 并传入指定数据 // 传入不同类型值 就需要先定义好 导致代码冗余不利于维护 function fn(n: number | string): number | string { return n; } fn(100); fn("abc"); // 通过泛型 解决 <T> 类似于类型变量 在传递时在确定是什么类型 // <T> 常规使用 T 是一个标识符可以自定义 function fn2<T>(n: T): T { return n; } fn2<number>(100); fn2<string>("abc"); // 多个参数情况 function fn3<T, G>(n: T, m: G): T { return n; } fn3<number, string>(100, "123"); fn3<string, boolean>("abc", true); // 泛型在类型别名上 type ObjType<A, B> = { name: A; getName: () => B; }; let obj: ObjType<string, number> = { name: "", getName() { return 123; }, }; // 泛型在接口上 // 可以设置默认类型 不传递时使用定义的默认类型 interface PersonItf<A, B, C = boolean> { name: A; age: B; sex: C; } let objs: PersonItf<string, number> = { name: "张三", age: 18, sex: false, };
type strOrnum = string | number;
interface PersonItf2<A extends strOrnum, B> {
name: A;
age: B;
}
let objss: PersonItf2<string, number> = {
name: "张三", //只能传递 string 和 number 类型 数据
age: 18,
};
- 有版本问题 待解决
- 类型兼容性 class
- TS采用的是结构化类型系统 类型检查关注的是值所具有的形状。在结构类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型
- 成员多的可以赋值给成员少的 (反之则不能)
- demo
class person1 { a: number; b: number } class person2 { a: number; b: number } const p: person1 = new person2() //非相同成员情况 class person1 { a: number; b: number } class person2 { a: number; b: number; c: number } const p: person1 = new person2()
- 接口兼容性 interface
- 接口之间的兼容性类似于 class 并且class 和 interface 之间也可以兼容
- demo
interface person2 { a: number b: number } class person3 { a: number; b: number; c: number } let p3:person2=new person3()
- 相同点: 都可以给对象指定类型
- 不同点:
- 1.接口 只能为对象指定类型 ,类型别名 可以为任意类型指定别名
- 2.类型别名不支持重复定义 ,接口可以