TypeScript是微软开发的JavaScript的超集,TypeScript兼容JavaScript,能够载入JavaScript代码而后运行。javascript
TypeScript与JavaScript相比进步的地方 包括加入注释,让编译器理解全部支持的对象和函数,编译器会移出注释,不会增长开销,增长一个完整的类机构,使之更新是传统的对象语言java
类 classes
接口interface
模块 modules
node
仍是由于是node.js开发,咱们要安装node的ts库, 为了强类型,主要仍是为了智能感知。程序员
npm install @types/node --dev-save
复制代码
npm install -g typescript
复制代码
npm update -g typescript
tsc -v
新建一个文件夹 tstypees6
npm init -y
复制代码
tsc --init
复制代码
会建立一个这样内容的tsconfig.jsontypescript
{
"compilerOptions": {
"module": "commonjs",
"target": "es6",
"removeComments": false,
"noImplicitAny": false,
"sourceMap": true,
"allowJs": true
},
"exclude": ["node_modules"]
}
复制代码
由于写node.js
你能够修改target
为es6
, 要调试把 sourceMap
改成true
, 添加allowjs
为true
,就能够ts和js混合用了.npm
初始化工程
npm init
tyc --init
ctrl + shift + b编译,能够选择watch或者buildjson
首先咱们了解一下JavaScript的基本数据类型数组
var isBoon: boolean = false; // 必须给一个初始化的值
console.log(isBoon);
复制代码
var num : number = 10;
console.log(num);
复制代码
var str:string="iwen"
console.log(str);
复制代码
let array1:Array<number>;
let array2:number[];
let array1:Array<number> = new Array<number>();
let array2:number[] = [1,2,3];
复制代码
enum Color {Red,Green,Blue};
var colorName: String = Color[1]
console.log(colorName);
// 获取枚举类型的值
enum ColorVal { Red=1, Green=2, Blue=5 };
var colorName:String = ColorVal[5]
console.log(colorName);
// 经过val值去获取key值
enum ColorKey { Red, Green, Blue}
var c:ColorKey = ColorKey.Green;
console.log(c);
// 获取枚举类型的下标
复制代码
var notSure:any =10;
notSure="hello";
notSure=false
console.log(notSure);
// 获得最后一次数据类型
复制代码
// 必须是指定的返回值
function tell():string{
return "hello"
}
// 能够没有任何返回值的话
function tellNull():void {
}
复制代码
在JavaScript中咱们学会了两种参数bash
function add(x,y) {
return x+y;
}
复制代码
var myAdd = function(x,y){
return x+y;
}
复制代码
// 设置变量,包括返回值
function add(x: number, y: number): number {
return x+y;
}
// 注解模式写法
var myAddts: (name: string, age: number)=>number=function(n:string,a:number):number{
return a;
}
复制代码
增长❓后变成,能够更变的值
function buildName(firstName:string,lastName?:string){
if (lastName) {
return `${firstName} ${lastName}`
}else{
return `${firstName}`
}
}
var name1 = buildName("ime","isee");
var name2 = buildName("im1")
复制代码
function buildName2(firstName: string, lastName ="isee") {
if (lastName) {
return `${firstName} ${lastName}`
} else {
return `${firstName}`
}
}
var name3 = buildName2("im1");
var name4 = buildName2("ime", "isee");
复制代码
function peopleName(firstName:string,...restOfname:string[]) {
return firstName + "" + restOfname.join(" ")
}
复制代码
var people ={
name:['iwen','ime','if','bean'],
getName:function(){
return ()=>{
var i = Math.floor(Math.random()*4)
return {
n:this.name[i]
}
}
}
}
复制代码
var people ={
name:['iwen','ime','if','bean'],
getName:()=>{
return ()=>{
var i = Math.floor(Math.random()*4)
return {
n:this.name[i]
}
}
}
}
复制代码
function attr(name:string):string; function attr(age: number): number; function attr(nameorage: any): any{
if (nameorage){
console.log(nameorage);
}
}
attr("姓名")
复制代码
class Person{
name:string;
age:number;
constructor(name:string,age:number) {
this.name = name;
this.age = age;
}
print(){
return this.name+":"+this.age
}
}
var p = new Person("a",12);
p.print();
复制代码
class Student extends Person{
school: string;
constructor(school: string) {
super('ime', 800); // 继承人类这个属性
this.school = school;
}
tell(){
return this.name + ":" + this.age + this.school;
}
}
var s = new Student("学校");
s.tell();
复制代码
关于类中成员访问修饰符:
ts类中成员(成员属性、成员方法)的访问修饰符,相似于java中类成员的访问修饰符,不一样的是ts中默认是被public修饰。
public :公有 在当前类里面、 子类 、类外面均可以访问
protected:保护类型 在当前类里面、子类里面能够访问 ,在类外部无法访问
private :私有 在当前类里面能够访问,子类、类外部都无法访问
class People{
private name:string; // 私有
public age:number; // 公有
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
print(){
return this.name+":"+this.age
}
}
复制代码
class Student extends People{
constructor() {
super('ads',200);
}
tell(){
return "222";
}
}
var s = new Student();
s.age = 12;
// s.name = 12; 此时是没法调用私有变量的
s.print();
console.log(s.print());
复制代码
class Hello{
private _name:string;
constructor() {
this._name= _name
}
set name(name:string){
this._name = name
}
get name():string{
return this.name
}
tell(){
return this._name;
}
}
var h = new Hello();
h.name='iwen';
console.log(h.tell());
复制代码
class Greeter{
greeting:string;
constructor(message:string) {
this.greeting = message
}
greet(){
return 'Hello,'+this.greeting;
}
}
var green:Greeter;
green=new Greeter('iwen');
console.log(green.greet());
复制代码
**咱们先定义个接口,而后把符合接口定义的对象传进去,这样能提升代码可读性。 **
须要注意的是:
若是咱们不给传进去的对象指定是接口类型的数据,那么传入的对象参数能够包含其余属性,编译器只会检查那些必需的属性是否存在,而且其类型是否匹配。
若是咱们给对象指定是接口类型的数据,那么,对象的属性必须和定义好的接口的必要属性一致。必要属性不能多也不能少。
function printeLabel(labelObj:{lable:string}) {
console.log(labelObj.lable);
}
var myObj = { lable:"Hello"}
printeLabel(myObj);
复制代码
interface LabelValue{
label:string
}
function printeLabel(labelObj:LabelValue) {
console.log(labelObj.label);
}
var myObj = {label:"Hello-1"};
printeLabel(myObj)
复制代码
在实际应用中,接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。在这种个状况下能够是用接口的可选属性去定义。
以下代码所示,name和age被定义为可选属性,那么在传对象的时候name和age就无关紧要。
interface USB{
name:string;
age?:number;
}
function printUSB(pu:USB){
console.log(pu.name);
console.log(pu.age);
}
var my = { name: "ime"}
printUSB(my)
复制代码
若是咱们但愿对象属性只能在对象刚刚建立的时候修改其值。 咱们能够在属性名前用 readonly来指定只读属性。
interface Point{
readonly x:number;
readonly y:number;
}
function getPoint(p:Point){
console.log(p.x);
console.log(p.y);
}
let point:Point={x:1,y:2};
// point.x=2;//错误 这里不能再子修改值
getPoint(point);
复制代码
只读数组也同样,一旦定义后不能再修改数组
let a:ReadonlyArray<number> =[1,2,3,4,5];
// a[0]=2;//不能再修改该数组
// a.length=20;
复制代码
接口能够描述javascript的任何对象,不只能描述对象的属性类型,固然也能描述对象的函数类型。
以下代码所示,接口描述了这个函数的参数类型和返回值类型
interface SearchFunc{
/*在这里咱们描述了这个接口有个函数 这个函数传进去2个string类型的参数 而后返回一个boolean类型的数据*/
(source:string,subString:string):boolean
}
var mySearch: SearchFunc;
mySearch = function (source: string, subString: string){
var result = source.search(subString);
if (result!=-1) {
return true
}
else{
return false
}
}
复制代码
跟接口描述函数类型差很少,咱们也能够描述那些可以“经过索引获得”的类型,好比经过下标获取数组中的值 a[2];须要注意的是,索引器的类型只能为 number 或者 string。
interface StringArray{
/*描述的一个数组 这个数组里面的元素是string类型 而且只能经过number类型来索引 [index:number]是索引器 string [index:number]:string; // age:number; //须要注意的是,当咱们将这个接口是数组类型时,那么,接口中定义的其它属性的类型都必须是该数组的元素类型。 这里的number类型是报错的 } var myArray: StringArray; myArray=['iwen','ime']; console.log(myArray[1]) 复制代码
所谓类类型,就是一个类去实现接口,而不是直接把接口拿来用,这更符合咱们的使用习惯。
interface IClock{
/*定义了一个接口 这个接口中有一个属性和一个方法*/
currentTime:Date;
getTime(d:Date);
}
/*Time类实现IClock接口*/
class Time implements IClock{
currentTime:Date;
getTime(d:Date){
this.currentTime=d;
}
}
复制代码
在TypeScript中,接口跟类同样是能够相互继承的, 这让咱们可以从一个接口里复制成员到另外一个接口里,能够更灵活地将接口分割到可重用的模块里。
/*接口能够继承接口 而且能够多继承*/
interface shape{
color:string;
}
interface pen extends shape{
width:number;
}
let circle=<pen>{};//注意这里的写法,建立一个对象并指定泛型 circle.color="red";//这里能够获取color属性 circle.width=2;//有width属性 复制代码
/*接口能够继承接口 而且能够多继承*/
interface shape{
color:string;
}
interface pen extends shape{
width:number;
}
interface Circle extends shape,pen{
point:number[];
}
let c=<Circle>{};//注意这里的写法,建立一个对象并指定泛型 c.point=[1,2]; c.color="red"; c.width=1; 复制代码
所谓的混合类型就是在一个接口中定义多种类型,好比属性,函数,数组等。
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter = <Counter>function (start: number) { }; counter.interval = 123; counter.reset = function () { }; return counter; } let c = getCounter(); c(10); c.reset(); 复制代码
泛型就是在编译期间不肯定方法的类型(普遍之意思),在方法调用时,由程序员指定泛型具体指向什么类型
在代码的过程当中,有些时候不肯定要传什么类型的参数,可是又但愿被校验
function Hello<T>(arg:T):T{
return arg;
}
var output = Hello<string>("Hello ime");
复制代码
function Hello<T>(str:T[]):T[] {
console.log(str.length);
return str
}
var list:Array<string> = Hello<string>(['1','2','3'])
for (let i = 0; i < list.length; i++) {
console.log(list[i]);
}
复制代码
class GetMin<T>{
arr:T[]=[];
add(ele:T){
this.arr.push(ele);
}
min():T{
var min=this.arr[0];
this.arr.forEach(function (value) {
if(value<min){
min=value;
}
});
return min;
}
}
var gm1= new GetMin<number>();
gm1.add(5);
gm1.add(3);
gm1.add(2);
gm1.add(9);
console.log(gm1.min());
var gm2= new GetMin<string>();
gm2.add("tom");
gm2.add("jerry");
gm2.add("jack");
gm2.add("sunny");
console.log(gm2.min());
复制代码
interface ConfigFn{
<T>(value:T):T;
}
var getData:ConfigFn=function<T>(value:T):T{
return value;
}
getData<string>('张三');
// getData<string>(1243); //错误
// 相似 Map<String,Object> Param 接口
interface Param{
[index:string]:any
}
复制代码
默认状况下,当你开始在一个新的 TypeScript 文件中写下代码时,它处于全局命名空间中。如在 foo.ts
里的如下代码:
const foo = 123;
复制代码
若是你在相同的项目里建立了一个新的文件 bar.ts
,TypeScript 类型系统将会容许你使用变量 foo
,就好像它在全局可用同样:
const bar = foo; // allowed
复制代码
毋庸置疑,使用全局变量空间是危险的,由于它会与文件内的代码命名冲突。咱们推荐使用下文中将要提到的文件模块。
它也被称为外部模块。若是在你的 TypeScript 文件的根级别位置含有 import
或者 export
,它会在这个文件中建立一个本地的做用域。所以,咱们须要把上文 foo.ts
改为以下方式(注意 export
用法)
export const foo = 123;
复制代码
在全局命名空间里,咱们再也不有 foo
,这能够经过建立一个新文件 bar.ts
来证实:
const bar = foo; // ERROR: "cannot find name 'foo'"
复制代码
若是你想在 bar.ts
里使用来自 foo.ts
的内容,你必须显式导入它,更新 bar.ts
以下所示:
import { foo } from './foo';
const bar = foo; // allow
复制代码
在 bar.ts
文件里使用 import
,不但容许你使用从其余文件导入的内容,并且它会将此文件 bar.ts
标记为一个模块,文件内定义的声明也不会污染全局命名空间。
export
关键字导出一个变量(或者类型):// foo.ts
export const someVar = 123;
export type someType = {
foo: string;
};
复制代码
export
的写法除了上面这样,还有另一种:// foo.ts
const someVar = 123;
type someType = {
type: string;
};
export { someVar, someType };
复制代码
// foo.ts
const someVar = 123;
export { someVar as aDifferentName };
复制代码
import
关键字导入一个变量或者是一个类型:// bar.ts
import { someVar, someType } from './foo';
复制代码
// bar.ts
import { someVar as aDifferentName } from './foo';
复制代码
// bar.ts
import * as foo from './foo';
// 你可使用 `foo.someVar` 和 `foo.someType` 以及其余任何从 `foo` 导出的变量或者类型
复制代码
import 'core-js'; // 一个普通的 polyfill 库
复制代码
export * from './foo';
复制代码
export { someVar } from './foo';
复制代码
export { someVar as aDifferentName } from './foo';
复制代码
我并不喜欢用默认导出,虽然有默认导出的语法:
export default
let/const/var
);// some var
export default (someVar = 123);
// some function
export default function someFunction() {}
// some class
export default class someClass {}
复制代码
import someName from 'someModule'
语法(你能够根据须要为导入命名):import someLocalNameForThisFile from './foo';
复制代码
大体上和es6一致