TypeScript介绍:
微软推出,JavaScript 的超集,其目的是为了更好的编写JavaScript,实际上最终运行在浏览器当中的仍然是JavaScript
官网:https://www.typescriptlang.org/
中文网:https://www.tslang.cn/docs/handbook/typescript-in-5-minutes.html【版本更新可能会比官网慢一些,版本会比较低】
TypeScript所应用于的框架:
Vue 、 React 、 Angular
TS的优点:
-
Type:类型
由于JavaScript中没有类型的概念,所以在类似于上述场景中就会出现很多错误,而TypeScript 中提供了类型的概念,因此可以规避这些错误。function add(a:number,b:number){ return a+b; } add(10,20); add(10,"20"); // TS中报错
-
面向对象
class(类) 、interface(接口)、 extends(继承)ES5 -> prototype function object (实现面向对象)
-
规避一些bug问题
类型错误:
js:执行的时候发生错误
ts:编译的时候就已经发生了错误
TypeScript安装
# 安装ts
npm install -g typescript
# 编译ts语法
tsc
编写hello.ts
function add(a, b) {
return a + b;
}
console.log(add(10,20));
控制台输入
tsc hello.ts
当前会目录生成一个 hello.js
控制台输入
node hello.js
修改代码
function add(a:number,b:number){
return a+b;
}
console.log(add(10,"20"));
编译报错
自动监听,避免每次修改代码之后都要重新编译
tsc -w hello.ts
TypeScript 中文学习网
Var、Let和Const
let和const是JavaScript里相对较新的变量声明方式。 像我们之前提到过的, let在很多方面与var是相似的,但是可以帮助大家避免在JavaScript里常见一些问题。 const是对let的一个增强,它能阻止对一个变量再次赋值。
/**
*
* var
* let
* 1.作用域变化 【var】作用域是函数级别 【let】作用域是花括号
* 2.let不允许重复定义
* const
* 1.constant:常量,定义之后不允许修改的值
*
*/
var num:number = 10;
console.log(num);
let age:number = 30;
console.log(age);
// if(true){
// let demo:string = 'demo'
// }
// console.log(demo); //编译报错
if(true){
let demo:string = 'demo'
console.log(demo);
}
// for(var i = 0;i<5;i++){
// setTimeout(function(){
// console.log(i);
// })
// }
for(let i = 0;i<5;i++){
setTimeout(function(){
console.log(i);
})
}
var num:number = 40;//var可以重复定义
const url:string = "http://iwenwiki.com";//常量不允许重定义,
// url = "http://iwens.org";
console.log(url);
Array(数组)
TypeScript像JavaScript一样可以操作数组元素。 有两种方式可以定义数组。 第一种,可以在元素类型后面接上 []
,表示由此类型元素组成的一个数组:
/**
* 数组:
* 数组的声明两种方式
* let names:string[] = ["iwen","ime"];
* let list:Array<number> = [10,20,30];
*
* 一组数据
* 一组相同类型的数据
*
*/
let names:string[] = ["iwen","ime"];
let list:Array<number> = [10,20,30];
// console.log(names[0]);
// console.log(list[2]);
names.push("frank");
// names.push(100);
console.log(names);
names.map(function(ele,index){
console.log(ele);
})
Tuple(元组)
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为 string和number类型的元组。
/**
* 元组
* 元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同
*/
let info:[string,number,boolean] = ['iwen',20,true];
console.log(info[1]);
info.filter(function(ele){
console.log(ele);
})
Function(函数)
和JavaScript一样,TypeScript函数可以创建有名字的函数和匿名函数。 你可以随意选择适合应用程序的方式,不论是定义一系列API函数还是只使用一次的函数。
我们可以给每个参数添加类型之后再为函数本身添加返回值类型。 TypeScript能够根据返回语句自动推断出返回值类型,因此我们通常省略它。
函数类型包含两部分:参数类型和返回值类型。 当写出完整函数类型的时候,这两部分都是需要的。 我们以参数列表的形式写出参数类型,为每个参数指定一个名字和类型。 这个名字只是为了增加可读性。 我们也可以这么写:
let myAdd: (baseValue: number, increment: number) => number =
function(x: number, y: number): number { return x + y; };
只要参数类型是匹配的,那么就认为它是有效的函数类型,而不在乎参数名是否正确。
第二部分是返回值类型。 对于返回值,我们在函数和返回值类型之前使用( =>
)符号,使之清晰明了。 如之前提到的,返回值类型是函数类型的必要部分,如果函数没有返回任何值,你也必须指定返回值类型为 void而不能留空。
函数的类型只是由参数类型和返回值组成的。 函数中使用的捕获变量不会体现在类型里。 实际上,这些变量是函数的隐藏状态并不是组成API的一部分。
/**
* 函数
* 1.函数的声明,函数中的参数类型限定
* 2.箭头函数 () => {} 箭头函数解决this问题
* 3.函数的返回值问题:void
* 4.可选参数和Rest Parameters
*/
// function add(a:number,b:number = 10){
// return a+b
// }
// const add = (a:number,b:number) => {
// return a+b
// }
// console.log(add(10,20));
// setTimeout(() => {
// console.log(100);
// },3000)
// let obj = {
// username:"iwen",
// getName:function(){
// setTimeout(() => {
// console.log(this.username);
// })
// }
// }
// obj.getName()
// function add(a:number,b:number):string{
// return a.toString()+b.toString();
// }
// var sum = add(10,20);
// // console.log(sum.toFixed(2));
// console.log(sum.substr(0,3));
// function add(a:number,b:number):void{
// console.log(a+b);
// }
// add(10,20);
// function add(a:number,...num:number[]):number{
// return num.reduce(function(sum,n){
// return sum + n;
// },a)
// }
// console.log(add(10,20,30,40,50));
function add(a:number,b?:number):number{
if(b){
return a+b
}else{
return a;
}
}
console.log(add(10));
Any类型
有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 这些值可能来自于动态的内容,比如来自用户输入或第三方代码库。 这种情况下,我们不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查。 那么我们可以使用 any类型来标记这些变量:
let a: any;
a = 10;
a = "Hello iwen";
a = [10,20];
console.log(a);
// 我们的使用Any类型的时候一定要注意,需要自己去处理类型判断的问题
const log = (value : any) => {
console.log(typeof value);
if(typeof value === 'number'){
return `数字类型:${value}`
}
if(typeof value === "string"){
return `字符串类型:${ value }`
}
throw new Error("类型错误");
}
let b:any[];
b = [10,'123',true];
console.log(b);
UnionType
function isNumber(value:any):value is number{
return typeof value === "number";
}
function isString (value:any):value is string{
return typeof value === 'string';
}
// 数字 字符串
const log = (value : string | number ) => {
console.log(typeof value);
if(isNumber(value)){
return `数字类型:${value}`
}
if(isString(value)){
return `字符串类型:${ value }`
}
// throw new Error("类型错误");
}
console.log(log(undefined));
Class基本概念
从ECMAScript 2015,也就是ECMAScript 6开始,JavaScript程序员将能够使用基于类的面向对象的方式。 使用TypeScript,我们允许开发者现在就使用这些特性,并且编译后的JavaScript可以在所有主流浏览器和平台上运行,而不需要等到下个JavaScript版本。
// es6 http://es6.ruanyifeng.com/#docs/class
class Person{
age:number;
name:string;
}
// 类的概念:
let p = new Person();
p.name = 'iwen';
p.age = 30;
console.log(p.name,p.age);
Constructor
构造函数:
随着类的实例化而自动执行的函数
/**
* 玩游戏的时间管理
*
*/
class Game{
name:string;
play_time:number;
/**
* 构造函数:
* 随着类的实例化而自动执行的函数
*/
constructor(name,play_time){
// this 指向生成的Object本身
this.name = name;
this.play_time = play_time;
}
getPlayTime(){
return `时间:${this.play_time}分钟`;
}
// 额外申请游戏时间
incremntPlayTime(){
this.play_time += 10;
}
}
let xiaoming = new Game("小明",20);
console.log(`姓名:${xiaoming.name}`);
xiaoming.incremntPlayTime(); // 增加10分钟
console.log(xiaoming.getPlayTime());
let xiaohua = new Game("小花",60);
console.log(`姓名:${xiaohua.name}`);
xiaohua.incremntPlayTime();
xiaohua.incremntPlayTime();
xiaohua.incremntPlayTime();
console.log(xiaohua.getPlayTime());
OOP_Extends
继承:
/**
* 把类看成一个模板
* worker
* student
*/
class Person{
name:string;
age:number;
say(){
console.log("我是说话");
}
hello(){
console.log("hello World");
}
}
class Student extends Person{
// 就近原则
say(){
console.log("我是student的say方法");
}
hello(){
console.log("student Hello");
}
studentHello(){
super.hello(); // 强行调用父类的方法
}
}
// 多态
let s:Person = new Student();
s.say();
Member Visibility
修饰符:
/**
* Public:
* 在任意地方都可以访问
* private:
* 只能在类的内部读取,不可以在外部读取,如果想读取,就在类的内部提供public的函数进行访问
* protected:
* 可以在类的内部访问,也可以在子类中进行访问
*
*
* 三者关系:Public > protected > private
*
*/
class Person{
protected name:string;
protected age:number;
// set和get方法
protected setName(name){
this.name = name;
}
protected getName():string{
return this.name;
}
protected say(){
console.log(`hello:${this.getName()}`);
}
}
class Student extends Person{
setStudentName(name){
this.name = name;
}
getStudentName(){
console.log(this.name);
}
}
let s = new Student();
s.setStudentName("iwen");
s.getStudentName();
Static
/**
* static
* 脱离了类的实例化而被调用的
* 类名.属性或者方法名
*/
class Person{
name:string;
age:number;
private static all:string = "这是一个全新的属性";
public static say(){
console.log(Person.all);
}
constructor(name,age){
this.name = name;
this.age = age;
}
getName():string{
return this.name;
}
}
class Student extends Person{
constructor(name,age){
super(name,age)
}
}
// console.log(Person.all);
Person.say();
ReadOnly
只读属性:
class Person{
name:string;
age:number;
// 不可以被修改的
readonly hello:string = 'Hello ReadOnly';
}
let p = new Person();
// p.hello = 'hello';
p.name = 'iwen';
console.log(p.hello);
console.log(p.name);
Enum
枚举:
/**
* 一周7天
* 使用:三种状态
*/
enum DaysOfTheWeek{
SUM,MON,TUE,WED,THU,FRI,SAT
}
/**
*
* {
* 0:SUM,
* 1:MON,
* ...
* }
*/
console.log(DaysOfTheWeek.MON);
let day:DaysOfTheWeek;
day = DaysOfTheWeek.SAT
// 可读性
if(day === DaysOfTheWeek.SAT){
// todo
}
ts-node_nodemon
npm install -g ts-node
ts-node: ts-node filename.ts//不需要每次编译
npm install -g nodemon
nodemon: nodemon --exec ts-node filename.ts//一次性直接运行,修改代码自动运行
增加nodemon的配置文件:配置快捷执行方案:npm run dev
class Hello{
name:string;
constructor(name){
this.name = name;
}
say(){
console.log(this.name);
}
}
let h = new Hello("iwen");
h.say();
/**
* ts-node:ts-node filename.ts
* nodemon:nodemon --exec ts-node filename.ts
* 增加nodemon的配置文件:配置快捷执行方案:npm run dev
*/
interface1
接口:
/**
* 鸭子类型:
* 接口:通过的规范
* USB接口:U盘 打印机 ...
*
* ts:编译时候直接报错,而非在运行过程中因为某些不确定的因素而报错
*/
interface Named{
// 属性
name:string;
}
const sayName = (obj:Named) => {
console.log(obj.name);
}
const Person = {
name:'iwen',
age:20
}
const student = {
learn:"web",
name:"张三"
}
const demo = {
name:"hello"
}
class Teacher{
name:string;
age:number;
}
let t = new Teacher();
t.name = '张老师';
sayName(Person);
sayName(student);
sayName(t);
sayName(demo); // undefined
interface2
interface INamed{
// 属性
name:string;
// 方法 在接口中,定义方法是没有方法体的 但是返回值和类型一定要添加
print(name:string):void;
}
const sayName = (obj:INamed) => {
obj.print(obj.name);
}
const person = {
name:"iwen",
age:20,
print(name){
console.log(name);
}
}
class Student{
name:string;
age:20;
print(name){
console.log(name);
}
}
let s = new Student();
s.name = 'iwen';
sayName(person);
sayName(s);
Type Alias
类型别名:
// type Name = string;
// let myName:Name = 100;
// console.log(myName);
type User = {
name:string;
age:number
}
// type User = {
// emial:string;
// }
const adminUser:User = {
name:'iwen',
age:20
}
interface IUser {
name:string;
age:number
}
interface IUser{
email:string;
}
const interUser:IUser = {
name:"iwen",
age:20,
email:"iwen@iwenwiki.com"
}
console.log(interUser);
interface3
interface IPerson{
name:string;
say():void;
}
const sayWath = (content:IPerson) => {
content.say();
}
class Student implements IPerson{
name:string;
say(){
console.log("我要讨论学习");
}
}
class Tearch implements IPerson{
name:string;
say(){
console.log("如何教好学生");
}
}
let s = new Student();
s.say();
sayWath(s);
let t = new Tearch();
t.say();
sayWath(t);
interface4
interface Person{
// 只读属性
readonly learn:string;
name:string;
// 可选属性
age?:number;
say():void;
hello?():string;
}
class Student implements Person{
name:string;
learn:string;
say(){
console.log("say");
}
}
let s:Person = new Student();
s.name = "iwen";
// s.learn = "web";
console.log(s.name);
s.say();
类型推断(断言)
断言和类型转换有点相似,但是并非真正的类型转换
/**
* 断言和类型转换有点相似,但是并非真正的类型转换
*
*/
let x:any = "hi iwen";
// 编译的时候,是不知道什么类型的!!!
let s = (<string>x).substring(0,2);
function getLength(something:string|number):number{
if((<string>something).length){
return (<string>something).length;
}else{
return something.toString().length;
}
}
// console.log(getLength(200));
// 接口
interface Person{
name:string;
age:number;
}
let person = {} as Person;
person.name = "iwen";
person.age = 20;
// 第二种写法
let person1 = <Person> {
name:"iwen",
age:20
}
// 声明person2 是Person的类型
let person2:Person ={
name:"heloo",
age:20
}