NO1. ts的新功能
ts是一门编程语言,是js的超集,增加了类型判断,可以在任何操作系统,浏览器和主机上执行,但是先得编译成js
区别:
①js是一门弱语言,解释型语言。ts是一门强语言,编程语言。
②js在运行时报错,ts在编译代码时就会报错提示。
③js不支持es6模块,泛型,接口。ts支持。
TypeScript 是一种给 JavaScript 添加特性的语言扩展。增加的功能包括:
类型批注和编译时类型检查
类型推断
类型擦除
接口
枚举
Mixin
泛型编程
名字空间
元组
Await
NO2. ts环境搭建
Ts是js的超集,为js添加了类型系统
由于浏览器/node不认识ts,需要安装解析ts的工具包
先设置一下淘宝镜像:
npm config set registry https://registry.npm.taobao.org
然后安装:
npm install -g typescript //之后敲回车
接下来新建一个ts文件,写一点东西,怎么让这个文件运行起来呢? ,先把ts转为js再运行
执行这个会根据ts文件生成一个js文件:
tsc hello.ts (文件名)
结果出现报错:
PS C:\Users\acer\Desktop> tsc hello.ts
tsc : 无法加载文件 C:\Users\acer\AppData\Roaming\npm\tsc.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅
https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。
所在位置 行:1 字符: 1
1. tsc hello.ts
2. ~~~
+ CategoryInfo : SecurityError: (:) [],PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess
PS C:\Users\acer\Desktop> set-executionpolicy remotesigned
解决办法如下:
1.以管理员身份打开vs -code
2.执行:get-ExecutionPolicy,显示Restricted,表示状态是禁止的;
3.执行:set-ExecutionPolicy RemoteSigned;
现在就可以了
接下来出现了一个hello.js文件,怎么执行这个文件?使用下面这个命令
node hello.js
但是每次修改了ts文件的内容都要执行两句指令,先转为js再运行ts
我们可以使用ts-node包简化
npm i -g ts-node
我们只要使用一句命令就可以执行ts-node hello.ts
使用这个命令我们看不到js文件,但是在底层实现.
接下来我们写一个变量:
let age :number = 18; //正数,附属,小数,整数
let name3 :string ='fp'; // 推荐使用单引号
let ye :boolean = true; // true false
let u :undefined = undefined; //只有一个值,为类型本身
let n :null = null ; //只有一个值,为类型本身
如果遇到问题,下面是更详细的文档
https://blog.csdn.net/weixin_42450034/article/details/107525517
NO3. 基本语法规则
TypeScript 会忽略程序中出现的空格、制表符和换行符。
TypeScript 区分大写和小写字符
面向对象主要有两个概念:对象和类。
对象:对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有色名字、品种;行为有:摇尾巴、叫、吃等。
类:类是一个模板,它描述一类对象的行为和状态。
方法:方法是类的操作的实现步骤。
NO4. TS的数据类型
基本数据类型
let age:number =18;
let user:string='fp';
let isHot:boolean=true;
const u:undefined = undefined;
只有null和 undefined类型的数据可以设置为null或undefined,其他类型不行
let x:number | null 除非支持多种类型 const obj:null = null;
引用数据类型 (object)
// Array语法:数组中类型一致
const arr1:number[]=[1,2,3]
const arr2:Array<string> = ['1','2']
const arr3:any[] =[1,'3']
//元组tuple 允许一个数组保存多个类型的数据,但是数量位置和类型需要一一对应
const arr4:[string,number,undefined] = ['2',6,undefined]
//对象类型,需要定义出对象有哪些属性每个属性的值的类型
const student:{id:number,name:string} = {id:1,name:'li'}、
//enum枚举
enum Gender {
male = 1, // 男
female = 0 // 女
}
enum OrderState {
fail = 0,
success =1,
timeout = 2
}
const people :{id:number,name:string,gender:Gender} = {id:1,name:'ll',gender:Gender.female}
特殊数据类型
//第一种:void 用来表示没有任何数据类型。
//通常,当一个函数没有返回值的时候,我们会将返回值的类型设置为 void。
//申明为voild类型的变量,只能赋值undefined和null
function warn():void {
console.log('no');
}
const a:void = undefined;
//第二种:any 来表示任意数据类型。
//通常,只有当值来自于一些动态的内容,我们在一开始确定不了值的类型,可以选择使用 any。
//其他情况下都不推荐使用 any
let b:any =true;
//第三种:never 表示永远不会有值的一种类型,是那些总是会抛出异常或根本就不会有返回值的函数表//达式或箭头函数表达式的返回值类型
//void 表示没有任何类型,never 表示永远不存在的值的类型
function error (message:string):never {
throw new Error(message);
}
const foo = 123;
if (foo !== 123) {
const bar = foo; // bar: never
}
NO5. 变量声明
情况1:声明变量的类型,但没有初始值,变量值会设置为 undefined:
var uname:string;
情况2:声明变量并初始值,但不设置类型,该变量可以是任意类型:
var uname = "Runoob";
情况3:变量不要使用 name 否则会与 DOM 中的全局 window 对象下的 name 属性出现了重名。
情况4:TypeScript 遵循强类型,如果将不同的类型赋值给变量会编译错误,
var num:number = "hello" // 这个代码会编译错误
情况5:类型推断 :当类型没有给出时,TypeScript 编译器利用类型推断来推断类型
var num = 2; // 类型推断为 number
console.log("num 变量的值为 "+num);
num = "12"; // 编译错误
console.log(num);
情况6:类型断言
TypeScript 允许你覆盖它的推断,毕竟作为开发者你比编译器更了解你写的代码。
类型断言主要用于当 TypeScript 推断出来类型并不满足你的需求,你需要手动指定一个类型。
类型断言有两种方式:
方式一: 使用"尖括号"语法
let strValue = 'this is a string type';
let strLength = (<string>strValue).length;
方式二:使用as
let strValue: any = 'this is string type';let strLength: number = (strValue as string).length;
情况7:非空断言
x! 将从 x 值中排出 null 和 undefined。
function myFn(msg: string | undefined | null) {
const str: string = msg; // Type 'undefined' is not assignable to type 'string'
const str: string = msg!; // ok
NO6. 变量作用域
var global_num = 12 // 全局变量
class Numbers {
num_val = 13; // 实例变量
static sval = 10; // 静态变量
storeNum():void {
var local_num = 14; // 局部变量
}
}
console.log("全局变量为: "+global_num)
console.log(Numbers.sval) // 静态变量
var obj = new Numbers();
console.log("实例变量: "+obj.num_val)
NO7. 运算符
和js几乎一样
https://www.runoob.com/typescript/ts-operators.html
NO8. 条件语句
if 语句- 只有当指定条件为 true 时,使用该语句来执行代码
if…else 语句- 当条件为 true 时执行代码,当条件为 false 时执行其他代码
if…else if…else 语句- 使用该语句来选择多个代码块之一来执行
switch 语句- 使用该语句来选择多个代码块之一来执行
NO9. 循环语句
break和contine的区别?
continue用于退出当前循环返回循环起始继续执行。break用于退出当前循环,
for(let i =1;i<=5;i++) {
if(i===2) continue;
console.log(i) // 1,3,4,5
}
for(let i =1;i<=5;i++) {
if(i===3) break;
console.log(i) // 1,2
}
//第一种for循环
for(let i:number=0;i >10;i--) {
number*=i;
//console.log(number);
}
//第二种for ..in 循环,迭代输出
let j :string; // val必须是string 或者any
let n :number[]=[1,2,3]
for (j in n) {
}
// 第三种 for ..of es6引入了这个来代替for in和forEach 他循序遍历数组,字符串,map映射,sets集合等等
let someArray = [1,'string',false];
for (let i of someArray) {
//console.log(i);
}
// forEach
someArray.forEach(element => {
//console.log(element + '哪些东西');//这个element 默认就是数组里面的元素,参数有(element,index,array)
});
// every
someArray.every(element=> {
//console.log(element + 'every'); //好像只能处理数值类型的元素
})
//while 循环
while(number>=1) {
//如果不满足条件不进入
}
// do while
do {
//执行一次再判断
}while(number>=1)
NO10. 函数
常规函数:
定义参数:
1.参数类型,如果我们定义了参数,则我们必须传入这些参数,除非将这些参数设置为可选(可选参数使用问号标识 ?)
2.也可以使用默认参数,如果没有传入使用默认值 param2[:type] = default_value
3.如果不知道参数会传入几个,可以使用剩余参数 …xx:string[] 但是传入参数的时候不需要写数组,直接(1,2)这样就行
定义返回值:
写在参数的后面
function greet (user:string='aa',age?:number,...rest:string[]):string {
return `名字${user},年龄${age},${rest}`
}
console.log(greet('li',3,'1','2'));
匿名函数
/* 匿名函数自调用 */
(function () {
let x ='hello';
console.log(x);
})()
构造函数
// 第一个参数是参数列表,第二个参数是包含函数定义js语句的字符串
var myFn = new Function('a','b','return a*b') ;
let x = myFn('2','5');
递归函数
/* 递归函数 */
function digui(number) {
if(number<=0) {
return 1
}else {
return number*(digui(number-1))
}
}
lamada函数
/* lamada函数,就是箭头函数,参数也可以不指定类型 */
let fun = (x:number)=> {
}
NO11. number
emp.prototype.email='admin@runoob.com';//在原型上添加属性
let text = 1225.30;
let val = text.toExponential();//转为指数计数法 1.2253e+3enu
console.log('text.toFixed(2)');//转为字符串,指定小数位
console.log(text.toLocaleString()); //数字转为字符串
console.log(text.toPrecision(2));//数字格式化为指定长度
console.log(text.toString()) // 数字转成字符串,默认是10进制
console.log(text.valueOf());//返回原始数据
NO12. string
// valueOf()返回指定字符串对象的原始值。
var str = new String("Runoob");
console.log(str.valueOf( )); // Runoob
// substring()提取字符串中两个指定的索引号之间的字符。
var str = "RUNOOB GOOGLE TAOBAO FACEBOOK";
console.log("(1,2): " + str.substring(1,2)); // U
// split()把字符串分割为子字符串数组。
var str = "Apples are round, and apples are juicy.";
var splitted = str.split(" ", 3);
console.log(splitted) // [ 'Apples', 'are', 'round,' ]
// search()
检索与正则表达式相匹配的值
var re = /apples/gi;
var str = "Apples are round, and apples are juicy.";
if (str.search(re) == -1 ) {
console.log("Does not contain Apples" );
}
// match()查找找到一个或多个正则表达式的匹配。
var str="The rain in SPAIN stays mainly in the plain";
var n=str.match(/ain/g); // ain,ain,ain
// concat()
连接两个或更多字符串,并返回新的字符串。
var str3 = str1.concat( str2 );
console.log("str1 + str2 : "+str3) // RUNOOBGOOGLE
// charAt()返回在指定位置的字符。
var str = new String("RUNOOB");
console.log("str.charAt(0) 为:" + str.charAt(0)); // R
NO12. array
// 数组解构
var arr:number[] = [12,13]
var[x,y] = arr // 将数组的两个元素赋值给变量 x 和 y
使用for....in迭代
var j:any;
var nums:number[] = [1001,1002,1003,1004]
for(j in nums) {
console.log(nums[j])
// 多维度数组
var multi:number[][] = [[1,2,3],[23,24,25]]
数组常用方法:
// concat()连接两个或更多的数组,并返回结果。
var alphaNumeric = alpha.concat(numeric);
// every()检测数值元素的每个元素是否都符合条件。
// filter()检测数值元素,并返回符合条件所有元素的数组
function isBigEnough(element, index, array) {
return (element >= 10);
}
var passed = [12, 5, 8, 130, 44].filter(isBigEnough);
console.log("Test Value : " + passed ); // 12,130,44
f// orEach()数组每个元素都执行一次回调函数。
// indexOf()搜索数组中的元素,并返回它所在的位置。如果搜索不到,返回值 -1,代表没有此项。
var index = [12, 5, 8, 130, 44].indexOf(8);
console.log("index is : " + index ); // 2
// join()把数组的所有元素放入一个字符串
var arr = new Array("Google","Runoob","Taobao");
var str = arr.join();
console.log("str : " + str ); // Google,Runoob,Taobao
// map()通过指定函数处理数组的每个元素,并返回处理后的数组。
var numbers = [1, 4, 9];
var roots = numbers.map(Math.sqrt);
console.log("roots is : " + roots ); // 1,2,3
// lastIndexOf()返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。
var index = [12, 5, 8, 130, 44].lastIndexOf(8);
console.log("index is : " + index ); // 2
// pop()删除数组的最后一个元素并返回删除的元素。
var element = numbers.pop();
// push()向数组的末尾添加一个或更多元素,并返回新的长度
// reduce()将数组元素计算为一个值(从左到右)。
var total = [0, 1, 2, 3].reduce(function(a, b){ return a + b; });
console.log("total is : " + total ); // 6
// reverse()反转数组的元素顺序。
var arr = [0, 1, 2, 3].reverse();
console.log("Reversed array is : " + arr ); // 3,2,1,0
// slice()选取数组的的一部分,并返回一个新数组。
var arr = ["orange", "mango", "banana", "sugar", "tea"];
console.log("arr.slice( 1, 2) : " + arr.slice( 1, 2) ); // mango
// shift()删除并返回数组的第一个元素
// sort()对数组的元素进行排序。var sorted = arr.sort();
// splice()从数组中添加或删除元素。
var arr = ["orange", "mango", "banana", "sugar", "tea"];
var removed = arr.splice(2, 0, "water");
console.log("After adding 1: " + arr ); // orange,mango,water,banana,sugar,tea
console.log("removed is: " + removed);
// unshift()向数组的开头添加一个或更多元素,并返回新的长度
var arr = new Array("orange", "mango", "banana", "sugar");
var length = arr.unshift("water");
NO13. map
和js的一样
map.clear()– 移除 Map 对象的所有键/值对 。
map.set()– 设置键值对,返回该 Map 对象。
map.get()– 返回键对应的值,如果不存在,则返回 undefined。
map.has()– 返回一个布尔值,用于判断 Map 中是否包含键对应的值。
map.delete()– 删除 Map 中的元素,删除成功返回 true,失败返回 false。
map.size– 返回 Map 对象键/值对的数量。
map.keys()- 返回一个 Iterator 对象, 包含了 Map 对象中每个元素的键 。
map.values()– 返回一个新的Iterator对象,包含了Map对象中每个元素的值 。
//map对象
let myMap = new Map([
["key1", "value1"],
["key2", "value2"]
]);
console.log(myMap.set("key3","value3")); //设置键值对,返回该 Map 对象
console.log(myMap.get('key1')); // 返回键对应的值,如果不存在,则返回 undefined。
console.log(myMap.has('key3')); // 返回一个布尔值,用于判断 Map 中是否包含键对应的值。
console.log(myMap.keys());//返回一个 Iterator 对象, 包含了 Map 对象中每个元素的键 。
console.log(myMap.values());//返回一个新的Iterator对象,包含了Map对象中每个元素的值 。
NO13. 元组
就是一个数组,存储的数据是不同的数据类型
访问元组
var mytuple = [10,"Runoob"]; // 创建元组
console.log(mytuple[0])
console.log(mytuple[1])
// 新增和删除
mytuple.push(12)
mytuple.pop()
// 更新元组
mytuple[0] = 121
// 解构元组
var a =[10,"Runoob"]
var [b,c] = a
NO14. 联合类型
test:Type1|Type2|Type3 // 指定多种数据类型
var arr:number[]|string[];
var val:string|number
NO15. 接口
就是定义一个类的结构,所有的属性不能有实际的值,方法都是抽象方法,可以被对象引用和实现实现接口就是使一个类满足接口限制,其实就是在限制对象内部属性的类型,更加严格。
interface Person {
grade:number,
say:()=>string,
commandline:string[]|string|(()=>string); //联合类型
}
var student2: Person = {
grade:8,
say:():string=>{return 'ho'},
commandline:'联合类型'
}
// 数组的方式:
interface namelist {
[index:number]:string
}
// 类型一致,正确
// var list2:namelist = ["Google","Runoob","Taobao"]
// 错误元素 1 不是 string 类型
// var list2:namelist = ["John",1,"Bran"]
// 继承
interface IParent1 {
v1:number
}
interface IParent2 {
v2:number
}
interface Child extends IParent1, IParent2 { }
var Iobj:Child = { v1:12, v2:23}
console.log("value 1: "+Iobj.v1+" value 2: "+Iobj.v2)
// 函数接口
interface SumInterface {
(a:number, b:number):number
}
// 建议使用这种写法
let sum:SumInterface= function(x,y) {
return x + y;
}
let res = sum(10, 20);
console.log(res);
NO16. 接口和类的区别
接口不包方法的具体实现,类实现具体的方法,实现接口,类通过implements
interface ContentInterface {
getContent(): String;
}
class Article implements ContentInterface {
// 必须实现getContent方法
public function getContent(): String {
return 'I am an article.';
}
function print(obj: ContentInterface): void {
// 实现了ContentInterface的对象是一定有getContent方法的
console.log(obj.getContent());
}
let a = new Article();
print(a)
NO17. 类
和js中的一样
class Cats extends Animals{
super(),
constructor(age) {
this.age=age;
}
static say() {
console.log('静态方法');
}
}
访问控制修饰符
public(默认)公有,可以在任何地方被访问。
protected 受保护,可以被其自身以及其子类访问。
private 私有,只能被其定义所在的类访问。
class Encapsulate {
str1:string = "hello"
private str2:string = "world"
}
var obj = new Encapsulate()
console.log(obj.str1) // 可访问
console.log(obj.str2) // 编译错误, str2 是私有的
抽象类,使用abstract定义,不能直接new实例化,只能被子类继承,且需要包含抽象类的抽象方法
abstract class Person {
//abstract skill();//缺少返回类型批注的构造签名隐式具有返回类型 "any"
abstract skill(): void;
}
const person = new Person();//报错Cannot create an instance of an abstract class.
abstract class Person {
same() {
console.log('子类中相同方法提取')
this.skill();//子类中不同方法处理
}
abstract skill(): void;
}
class Student extends Person {
skill(){
console.log('单独处理');
}
NO18. 命名空间
如果有两个重名的定义,我们加上namespace 命明空间,相当于一个新的空间中定义标识符
一个最明确的目的就是解决重名问题,不同名字空间中的含义是互不相干的;需要在外部可以调用 命名空间中的类和接口,则需要在类和接口添加 export 关键字;命名空间本质上是一个对象,作用是将一系列相关的全局变量组织到一个对象的属性;
namespace someName {
如果需要在外部调用里面的接口就需要export导出
export interface ISomeInterfaceName {}
export class SomeClassName {}
命名空间可以嵌套使用,外部通过 . 来访问
export namespace invoice {
export class run {
public calculate() {
console.log('oo');
}
}
}
}
var s = new someName.invoice.run()
如果一个命名空间在一个单独的 TypeScript 文件中,则应使用三斜杠 /// 引用它,语法格式如下:
/// <reference path = "SomeFileName.ts" />
NO19. 模块
如果一个文件不带有顶级的import或者export声明,那么它的内容被视为全局可见的;任何包含顶级 import 或者 export 的文件都被当成一个模块;在不同的模块中我们可以申明同名的变量,但是必须使用 import 或者 export 导入导出;
// 文件名 : SomeInterface.ts
export interface SomeInterface {
// 代码部分
}
import someInterfaceRef = require("./SomeInterface"); 需要使用require引入
模块和命名空间比较:
共同点:都可以在内部进行封装,防止全局污染
区别:在命名空间中很难识别组件之间的依赖关系,而模块可以申明它的依赖
总结: 由于模块也能实现相同的功能, 所以大部分情况下用模块即可
NO20. 声明文件
TypeScript中的Declare关键字有什么作用?
当我们在ts项目中引入了一些第三方js库,引入后TypeScript 编译器仍会提示相应的错误信息。因为没有声明,ts编译器不认识这个变量
我们需要在 .d.ts 文件中声明,如 declare var wx:any;相当于声明了一个叫wx的全局变量;
在ts项目中引入其他模块,例如css、less等,TypeScript编译器将无法识别上述的这些模块,就会提示相应的错误信息。
所以我们需要 declare module ‘*.css’
声明文件或模块的语法格式如下:
declare module Module_Name {
}
TypeScript 引入声明文件语法格式
/// <reference path = " runoob.d.ts" />
NO21. 泛型
泛型可以理解为宽泛的类型,通常用于类和函数,就是我们在创建时不知道数据类型,用any的话就关闭了类型检查,这种情况就可以使用泛型
参数()前面是指定传入的类型,后面是返回值的类型
function abc(value: number): number { return value; } //输入和输出都是number类型
function abc1(value: any): any { return value; } //输入和输出都是any类型,这样就丢失了一些信息:传入的类型与返回的类型应该是相同的
//给abc2添加了类型变量T,之后就可以使用这个类型,然后再次使用T当做返回值类型
function abc2<T>(value: T): T { return value; } //这就是泛型,可以适用于多个类型,同时输入的参数类型和返回值的类型是相同的
class Person<T>{
private _value: T;
constructor(val: T) {
this._value = val;
}
}
let p = new Person<number>(12)
如上,<T>表示传递一个T类型,在new的时候才把具体类型传入。其中T是变量可改,但通常比较常见就是写T之前说
TypeScript类型的时有说到数组,其实数组本质就是一个泛型类
function fn<T>(arg: T): T {
return arg;
}
fn<number>(12);
约束泛型:
// 需求: 要求指定的泛型类型必须有Length属性才可以
interface LengthInterface{
length:number
}
let getArray = <T extends LengthInterface>(value:T, items:number = 5):T[]=>{
return new Array(items).fill(value);
};
let arr = getArray<string>('abc');
// let arr = getArray<number>(6)
let res = arr.map(item=>item.length);
https://blog.csdn.net/m0_62346839/article/details/126443241 不懂看看