>  기사  >  웹 프론트엔드  >  Typescript 가이드가 자세히 설명되어 있습니다.

Typescript 가이드가 자세히 설명되어 있습니다.

零下一度
零下一度원래의
2017-06-30 10:48:242830검색

TypeScript 가이드

Foreword

TypeScript는 Anglejs2에 권장되는 스크립트 언어입니다. 2012년 마이크로소프트에서 처음 출시했다.

1. Typescript와 javascript의 차이점

1. 사양의 관점에서 보면:

Javascript는 ECMA5 사양을 따르며 TypeScript는 ECMA6의 구문 구현입니다.

2. 기능적으로 말하면:

TypeScript는 구성 요소 구축에 도움이 되는 클래스, 모듈 및 인터페이스를 제공하므로 객체 지향 프로그램을 더 쉽게 작성할 수 있으므로 더 나은 TypeScript라고 합니다.

3. 지원 측면에서:

모든 브라우저는 ES5 및 이전 버전의 javascript를 지원하지만 typescript를 지원하는 브라우저는 없으므로 컴파일이 필요합니다. 또한 typescript는 모든 javascript 구문을 지원합니다.

사진은 ES5, ES2015, ES2016과 TypeScript의 관계를 보여줍니다.

2. Typescript 설치 및 helloworld 프로그램

(1) npm 설치

 npm install -g typescript@1.8 全局安装了1.8版本的typescript编译器和tsc程序,并且添加到环境变量中。为了确认正常,打印-v命令。
$ npm -v   //首先看一下npm是不是新版本$ npm install -g typescript@1.8. //全局安装typescript$ tsc -v

표시되는 Typescript 버전은

(2) 첫 번째 TS 프로그램을 실행합니다.

첫 번째 방법.

먼저 1.hello.ts 프로그램에 입력하세요:

console.log("hello world!")

그런 다음 명령을 실행하세요:

$ tsc 1.hello.ts  //把ts文件转换为等价的hello.js

마지막으로 node를 실행하여 js 파일을 실행하세요.

$ node 1.hello.js //打印出hello world。成功!

두 번째 방법입니다.

먼저 typescript와 ts-node.

$ npm install typescript@1.8  -g    //装好ts$ npm install  -g ts-node //装ts-node模块,选项是-g哦。

를 설치한 후 명령 실행 파일을 실행하세요.

$ ts-node 1.hello.ts //打印hello world,成功!

3. ES2015 및 ES2016

ES2015 및 ES2016에서 TypeScript에 도입된 구문과 기능은 비교적 큰 변화를 가져왔습니다.

(1) ES2015의 Arrow 함수

Origin: JavaScript는 1차 함수의 특성을 가지고 있습니다. 즉 함수를 매개변수로 전달할 수 있기 때문에 사용법은 좋지만 너무 장황해서 ES2015에서는 arrow를 제공합니다. 기능이 더 간결해졌습니다.

ts 예시 1:

var even=[3,1,56,7].filter(el=>!(el%2));//对数组调用过滤器filter函数,!(el%2)只有偶数的取模操作为0,那么整体就是true,所以el获取的是偶数console.log(even);//打印56咯。

ts-node 명령을 실행하여 화면 표시 결과는 다음과 같습니다.

ts 예시 2:

var result=[1,2,3]
    .reduce((total,current)=>total+current,0);//reduce对每个数组元素比如1、2、3调用回调函数,初始值为0。//回调函数的参数是total和current,total是上一次回调函数的值,第一次就为初始值0.// current是当前数组元素的值。返回值是total+current。//那么就清晰了,第一个total为0,当前元素是1,返回的0+1.console.log(result);

ts-node 명령을 실행하면 화면이 표시됩니다. 결과는 다음과 같습니다.

ts 예 3:

var data=[
    {price:10,total:70},
    {price:94,total:340},
    {price:14,total:34}
];var sorted=data.sort((a,b)=>{//a、b为依次遍历的数组元素//这里的对象是函数体var diff=a.price-b.price;if(diff!==0){return diff;
    }return a.total-b.total;
})
console.log(sorted);

ts-node 명령을 실행(컴파일)하면 화면에 올바른 정렬 결과가 표시됩니다.

ts 예 4:

function MyComponent(){this.age=42;
    console.log(this);
    setTimeout(()=>{//箭头函数的特性,它的执行上下文指向外层的代码,即组件实例的this对象this.age+=1;
        console.log(this.age);
    },100);//等待100ms,age加1等于43,并打印出来}new MyComponent();

컴파일하면 화면에 다음과 같이 표시됩니다.

(2) ES2015 및 ES2016의 클래스

먼저 ES6이 ES2015라는 점을 설명하겠습니다. ECMAScript 6(이하 ES6)은 JavaScript 언어의 차세대 표준입니다. 현재 ES6 버전은 2015년에 출시되었기 때문에 ECMAScript 2015라고도 불립니다.

그렇다면 ECMAScript 2016은 ES7입니다.

ES6 클래스는 여전히 생성자와 프로토타입 기반 상속을 사용하지만 구문은 더 편리하고 간결합니다.

다음은 ES2016에서 클래스를 정의하는 구문입니다.

class Human{
    static totalPeople=0;
    _name;//ES2016的属性定义语法    constructor(name){this._name=name;
        Human.totalPeople+=1;
    }
    get name(){return this._name;
    }
    set name(val){this._name=val;
    }//name属性的get和set方法    talk(){return "Hi,I'm"+this.name;
    }
}
class Developer extends Human{
    _languages;//ES2016的属性语法    constructor(name,languages){
        super(name);this._languages=languages;
    }
    get languages(){return this._languages;
    }
    talk(){return super.talk()+" And I Know "+this.languages.join('.');

    }
}var human=new Human("foobar");var dev=new Developer("bar",["javascript"]);
console.log(dev.talk());

喜欢!除了类的定义体是对象外,属性和方法的书写和java很像,我喜欢的方式。

 通过编译,屏幕显示结果为:

(3)定义块级作用域中可见的变量

java和c++是块级作用域。

只列举代码,表现为2点,第一个是特定代码块的变量只能代码块内部可见,第二,嵌套在内部的代码块中也可见。

public class Demo{// 属性块,在类初始化属性时候运行    {int j = 2;// 块级变量    }public void test1() {int j = 3;  // 方法级变量if(j == 3) {//j变量在代码嵌套的内部if语句中可见int k = 5;  // 块级变量        }
}

javascript是函数作用域。

var fns=[];for(var i=0;i<5;i+=1){
    fns.push(function(){
        console.log(i);
    })
}
fns.forEach(fn=>fn());

打印结果,很奇怪。

ES6代码:

var fns=[];for(let i=0;i<5;i+=1){
    fns.push(function(){
        console.log(i);
    })
}
fns.forEach(fn=>fn());

打印结果:

(4)使用ES2016装饰器进行元编程。

装饰器是ES2016的一个提案,它的依据是“在设计阶段可以对类和属性进行注释和修改”。在angular2很常用,可用来定义组件、指令以及管道,并且还能配合依赖注入机制来使用。

首先,装饰器能干吗。

装饰器典型的用法是把方法和属性标记为过期,另一个应用场景是声明式语法,从而实现面向切面的编程。其实呢,装饰器只是一个语法糖而已。装饰器目前并没有得到真正的使用

Experimental support for decorators is a feature that is subject to change in a future release.
//编写了Person类,它只有一个getter,名字为kidCountclass Person{//kidCount有一个装饰器nonenumerable    @nonenumerable
    get kidCount(){return 42;
    }
}//装饰器函数接收3个参数,最后返回descriptor属性。function nonenumerable(target,name,descriptor){
    descriptor.enumerable=false;//可枚举性return descriptor;
}var person=new Person();for(let prop in person){
    console.log(prop);
}

对应的ES5语法类似于:

descriptor=nonenumerable(Person.prototype,'kidCount',descriptor);//descriptorObject.defineProperty(Person.prototype,'kidCount',descriptor);

接下来,介绍angular 2装饰器的用法。

"app""./app.html""/",component:Home,name:'home'"/",component:About,name:'about'

如果装饰器需要接收参数,那么就定义为接收参数的函数,然后由函数返回真正的装饰器。

 (5)使用ES2015编写模块化的代码

angular 1.x引入了一套模块系统,不过并不支持懒加载特性。angular 2种充分利用了ES2015提供的模块系统。ES2015提供了声明式API,以及使用模块加载器的命令式API。

语法分为export和import两个方面。

第一,看一个简单的DEMO:

math.ts:

export function square(x){return Math.pow(x,2);
}
export function log(x){return Math.log(x);
}
export const PI=Math.PI;

math2.ts,更简洁的写法而已:

function square(x){return Math.pow(x,2);
}function log(x){return Math.log(x);
}
const PI=Math.PI;
export {square,log,PI}

app.ts调用,要编译的是app.ts哦:

import {square,log} from "./math";
console.log(square(2));
console.log(log(100));

屏幕显示效果:

第二,ES2015模块化语法带有隐式的异步行为。

比如说,

A模块依赖于B、C模块。当用户请求A模块,JS模块加载器会先加载B和C模块,才能调用A模块。这里B和C模块都是异步加载的。

第三,典型的应用场景会给导出的内容起一个名字。

使用别名导入整个模块的DEMO:

import * as math from "./math";//as语法咯console.log(math.square(2));
console.log(math.log(100));

第四,默认导出。

模块导出使用了export default语法,是一种带名字的导出。

基本的默认导出DEMO:

math3.ts:

export default function cube(x){return Math.pow(x,3);//默认导出的名字是cube}
export function square(x){return Math.pow(x,2);
}

app3.ts:

import cube from "./math3";//等同于import {default as cube} from "./math3console.log(cube(3));

显示结果正常:

默认导出混合其他导出的DEMO:

math3.ts:

export default function cube(x){return Math.pow(x,3);//默认导出的名字是cube}
export function square(x){return Math.pow(x,2);
}
app4.ts:
import cube,{square} from "./math3";
console.log(square(2));
console.log(cube(3));

显示结果OK:

 (6)ES2015的模块加载器

通过编程的方式加载app模块执行main函数,使用System对象的import方法就好了。现在代码因为缺乏配置项,所以还运行不起来。

app.ts:

export function main(){
    console.log(2);
}

init.js

System.import("./app")
.then(app=>{
    app.main();
})
.catch(error=>{
   console.log("致命的错误"); 
});

四: 发挥静态类型的优势

有了静态类型,那么IDE开发环境除了避免输入错误的语法高亮,还提供精确静态分析的建议。很棒。

typescript的所有类型包含几类:

● 原生类型

● 组合类型

● Object类型

● 泛型

● any类型

(1)使用显式类型定义

除了webstorm报类型(type)错误,运行编译命令,typescript  也报错 Type 'string' is not assignable to type 'number' 。那么就是说,一旦foo设置了类型,就不能赋值为其他类型了。

(2)any类型

any类型是所有其他类型的父类,代表可以拥有任何类型的值,类似于动态类型,一方面不会报错,另一方面则放弃了typescript的优点了。

let foo:any;
foo={};
foo="bar";
foo+=24;
console.log(foo);//结果为"bar 24"。

(3)原生类型

就是javascript比较熟悉的Number、String、Boolean、Null、以及Undefined。而Enum是用户自定义的原生类型,它是Number的子类。含义是枚举用户自定义的类型,由一系列有名称的值也就是元素构成。

定义enum如下:

enum STATES{
    CONNECTING,
    WAITING,
    CONNECTED
}//定义枚举类型if(this.state==STATES.CONNECTING){//通过点语法引入}

(4)Object类型

首先,讲更加通用的Array类型,它是Object的子类。

Typescript的数组,要求元素类型相同。都可以使用js的各种数组方法,比如push、join、splice等,也可以使用方括号运算符对数组元素进行访问。

数值型数组DEMO:

let primes:number[]=[];
primes.push(2);
primes.push(3);
console.log(primes);

any型数组:

let randomItems:any[]=[];
randomItems.push(1);
randomItems.push("foo");
randomItems.push("{}");
console.log(randomItems);

屏幕结果为

第二,说Function类型,也是Object的子类哦。

javascript有两种方式创建新函数:

//函数表达式var isPrime=function(n){

}//函数声明function isPrime(n){
   
}//或者,使用箭头函数var isPrime=n=>{   //函数体}

Typescript增加的是参数和返回值的类型。

函数表达式:

let isPrime:(n:number)=>boolean=n=>{//整个函数赋给变量isPrime,参数是number类型的n,返回值是boolean类型的n,函数体在{}里面}

函数声明:

function isPrime(n:number):boolean{//参数为number类型,返回值为boolean类型}

对象字面量的定义写法:

let person={
     _name:null,
     setName(name:string):void{       //参数是string类型,返回值是void   this._name=name;
     }
}

(5)定义类

typescript定义类,属性的声明式强类型的。

 class-basic.ts:

class Human {
    static totalPeople=0;
    _name:string;//强类型的哦    constructor(name){      this._name=name;
      Human.totalPeople+=1;
    };
    get name(){return this.name;
    }
    set name(val){this._name=val;
    }
    talk(){return "HI,I'am"+this._name;
    }
}
let human=new Human("foo");
console.log(human._name);

打印结果为

成功

(6)访问修饰符

有3个。更好的实现封装和更优雅的接口。

●public。public的属性和方法在任何地方可以访问。

●private。private的属性和方法只能在类定义内部进行访问。

●protected。protected的属性和方法可以类定义内部访问,也可以从子类访问。

//typescript实现class Human{
    static totalPeople=0;
    constructor(protected name:string,private age:number){//定義了一個protected型的屬性,名為name,類型為string//age屬性。好處是避免显示式的赋值操作Human.totalPeople+=1;
    }
    talk(){return "Hi,I'm"+this.name;
    }
}
class Developer extends Human{
    constructor(name:string,private languages:string[],age:number){//显式使用访问修饰符,或者定义接收的参数类型,都可以混合使用的。        super(name,age);
    }
    talk(){return super.talk()+" And I Know "+this.languages.join('.');

    }
}//创建developer类的一个新实例let Dev=new Developer("foo",["javascript","Go"],42);//dev.languages=["java"];这行代码会报一个私有属性的错误let human=new Human("foo",42);//human.age=42;由于私有属性,所以报错//human.name="bar",会报一个protected错误。它只能在类类内部或者子类中访问

(6)接口

接口定义了一组对象共同的属性和方法,称作接口签名。要实现接口,那么实现定义接口规定的所有属性和方法。

关键字就2个,interface和implements。

interface Accountable1{
    goIncome():number;
    accountNumber:string
}
class Value implements Accountable1{
    constructor( public accountNumber:string){this.accountNumber=accountNumber;
    }
    goIncome():number{return 100;
    }
}var extra=new Value("余额");
console.log(extra.accountNumber);

打印为

接口实现,成功

接口继承

接口之间可以互相继承。接口继承另外一个接口,使用extends关键字。

interface-extends.ts:

interface Accountable2{
    accountNumber:string;
    getIncome():number;
}
interface Individual extends Accountable2{
    ssn:string;
}

实现多个接口:

interface People{
    age:number;
    name:string;
}
interface Accountable{
    accountNumber:string;
    goIncome():number
}
class Person implements People,Accountable{  //实现多个接口,用逗号分隔    age:number;
    name:string;
    accountNumber:string;
    constructor(age:number,name:string,accountNumber:string){

    }
    goIncome():number{return 10;
    }
}var person=new Person(10,"100","1000");

五: 使用类型参数编写泛型代码

 可以写类似java的泛型代码,好精彩!使用“”。能写出更简洁的代码来。

(1)使用泛型类

定义一组类型的class。

class Nodes<T> {
    value:T;
    left:Nodes<T>;
    right:Nodes<T>;
}
let numberNode=new Nodes<number>();

let stringNode=new Nodes<string>();

numberNode.right=new Nodes<number>();//类型匹配numberNode.value=42;//类型匹配//numberNode.value="42";报错,类型不匹配//numberNode.left=stringNode;报错,类型不匹配

(2)使用泛型函数

定义一组类型的函数。

function identify<T>(arg:T){return arg;
}
interface Comparable{
    compare(a:Comparable):number;
}function sort<I extends Comparable>(arr:Comparable[]){//}

(3)多重泛型

class Pair<K,V>{
    key:K;
    value:V;
}
let pair=new Pair<string,number>()
pair.key="foo";
pair.value=42;

精彩

五: 使用typescript的类型推断机制简化代码

typescript可以猜测代码中的静态类型。好智能哦,所以可以用来省略一些代码。

let answer=42;
answer="42";//会提示错误,因为一开始的赋值,typescript已经把它当做number类型了。let answer;
answer=42;
answer="42";//这个时候不会报错,因为第一次声明时,typescript给到的静态类型是any。

(1)最常见的类型

let x=["42",42];//x的类型推断为any[]数组。
let x=[42.null,32];//typescript的类型推断为number[]。

(2)与上下文有关的类型推断

 

这里可以看到e并没有规定类型,可是typescript就根据上下文推断它为MouseEvent鼠标事件。

六: 使用外部类型定义

尽管静态类型很酷,但是我们使用的大部分前端类库都是基于javascript构建的,都是动态类型。而typescript提供了额外的类型定义,来给编译器提供提示。

(1)使用预定义的外部类型定义

 step1:安装typings工具

npm install  -g  typings

于是就安装好了typings目录,tsconfig.json、typings.json中,内容为:

//tsconfig.json{  "compilerOptions": {"module": "commonjs","target": "es5","sourceMap": true
  },  "exclude": ["node_modules"
  ]
}
//typings.json{  "dependencies": {}
}

step2:创建基础配置

typings init

step3:搜索

$  typings search module

step4:安装is-builtin-module

$  typings install is-builtin-module  --save

这个时候,typings.json的内容变为

{  "dependencies": {"is-builtin-module": "registry:npm/is-builtin-module#1.0.0+20161031191623"
  }
}

typings目录变为

(2)自定义外部类型

step1:定义好类库的接口。

define-external-type.ts:

interface LibraryInterface{
    selectElements(selector:string):HTMLElement[];
    hide(element:HTMLElement):void;
    show(element:HTMLElement):void;
}

step2:定义ts.d文件。

interface DOMLibraryInterface{
    selectElements(selector:string):HTMLElement[];
    hide(element:HTMLElement):void;
    show(element:HTMLElement):void;
}
declare var DOM:DOMLibraryInterface;

 step3:DOM通过reference引入,编译器就会找到对应的外部类型定义了。

///<reference path="dom.d.ts" />var DOM={
    selectElements:function(selector:string):HTMLElement[]{return [];
    },
    hide:function(element:HTMLElement):void {
        element.hidden=true;
    }
};

这个时候,会报错。直到完全实现定义的接口为止,如下:

///<reference path="dom.d.ts" />var DOM={
    selectElements:function(selector:string):HTMLElement[]{return [];
    },
    hide:function(element:HTMLElement):void {
        element.hidden=true;
    },
    show:function(element:HTMLElement):void{
        element.hidden=false;
    }
};

这样分离出来,就可以把全部的外部类型定义放在同一个文件里,方便管理了。

위 내용은 Typescript 가이드가 자세히 설명되어 있습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.