黑马 typeScript 学习笔记

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 不懂看看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值