typescript

TypeScript是一种由微软开发的自由和开源的编程语言。它是JavaScript的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程。

它可以编译为JavaScript。是一种给JavaScript添加特性的语言扩展。它拥有以下特性:

  • 类型注释和编译时类型检查
  • 基于类的面向对象编程(很像java)
  • 泛型
  • 接口
  • 声明文件
  • ...

TypeScript的设计目的应该是解决JavaScript的“痛点”:弱类型和没有命名空间,导致很难模块化,不适合开发大型程序。另外它还提供了一些语法糖来帮助大家更方便地实践面向对象的编程。

ts是angular的默认开发语言,在即将面世的vue3也将使用js。

官方中文文档地址:

https://www.tslang.cn/index.html

1. 快速上手

1.1 安装

npm install -g typescript

创建一个 hello.ts

function greeter(person) {
    return "Hello, " + person;
}

let user = "Dang Jingtao";
document.body.innerHTML = greeter(user);

完全支持es5/6的写法。

1.2 编译

在命令行终端运行:

tsc hello.ts

编译完成后,生成了一个同名的js文件,这就是ts编译出来的JavaScript。

1.3 web应用上运行

greeter.html里输入如下内容:

<!DOCTYPE html>
<html>
    <head><title>TypeScript Greeter</title></head>
    <body>
        <script src="hello.js"></script>
    </body>
</html>

把你编译好的 hello.js文件在浏览器里打开 greeter.html运行这个应用即可。

2. 基本使用

2.1 类型注解和类型检查

类型推论——灵活的强类型语言:声明一个变量,但你没赋值时,一定要写类型。

let name1:string;
let name2='';

以上都默认声明了字符串的变量。都可以!

你也可以声明一个全部由字符串组成的变量:

let arr:string[]

如果你尝试给arr push一个数字,就会报错。

因此你只能 arr.push('1')

对于可能变化的类型变量;

可以用或符号 |

let foo:number|string;//可以是数字或字符串

也可以定义为 any

let foo:any;//
let arr:any[];//数组成员可以是任意类型

在看下官网的案例:

function greeter(person: string):string {
    return "Hello, " + person;
}

在参数之外加一个 :string表示期望返回值是个字符串。如果传进去的person是个数组,就报错。

如果我这段函数只是处理一个业务,不需要返回值,那可以这么写:

function greeter(person: string):void {
    alert(person)
}

ts常见的内置类型(开头都是小写): string,number,boolean,any,void

2.2 函数

现在看一个小学英语难度的案例:

function sayHi (name:string,age:number):string{
    return `hi! ${name}, i am ${age} years old`;
}
// sayHi('djtao') 报错

这个案例中,name和age是必填参数。

那么需要是可选参数,加上问号就行了。

function sayHi (name:string,age:number,addr?:string):string{
    return `hi! ${name}, i am ${age} years old`;
}

那如果我需要设置一个默认参数呢?比如默认30岁:

function sayHi (name:string,age:number=30,addr?:string):string{
    return `hi! ${name}, i am ${age} years old`;
}

也支持es6特性

如果一个函数,根据参数的数量,类型的不同,返回不同类型的数据,称为函数重载。

function foo(a:{name:string}):string;
function foo(a:string):object;
function foo(a:string|{name:string}):any{
    if(typeof a == 'object'){
        return a.name;
    }else if(typeof a== 'string'){
        return {name:a};
    }
}

等效于:

function foo(a) {
    if (typeof a == 'object') {
        return a.name;
    }
    else if (typeof a == 'string') {
        return { name: a };
    }
}

2.3 接口

关于接口,你可以描述为定义了属性和类型,但是没有定义其它任何东西的构造函数。

这里我们使用接口来描述一个拥有 firstNamelastName字段的 Person对象。 在TypeScript里,只在两个类型内部的结构兼容那么这两个类型就是兼容的。 这就允许我们在实现接口时候只要保证包含了接口要求的结构就可以,而不必明确地使用 implements语句。

interface Person {
    firstName: string;
    lastName: string;
}

function greeter(person: Person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

let user = { firstName: "Jane", lastName: "User" };

document.body.innerHTML = greeter(user);

在前后端联调时,接口可以很好的对数据类型进行规范。

2.4 类

最后,再看看ts中无处不在的类。

TypeScript支持JavaScript的新特性,比如支持基于类的面向对象编程。

让我们创建一个 Student类,它带有一个构造函数和一些公共字段。 注意类和接口可以一起工作,程序员可以自行决定抽象的级别。

还要注意的是,在构造函数的参数上使用 public等同于创建了同名的成员变量。

class Student {
    fullName: string;
    constructor(public firstName, public middleInitial, public lastName) {
        this.fullName = firstName + " " + middleInitial + " " + lastName;
    }
}

// 如同格式配置
interface Person {
    firstName: string;
    lastName: string;
}

function greeter(person : Person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

let user = new Student("Jane", "M.", "User");

document.body.innerHTML = greeter(user);

重新运行 tsc greeter.ts,你会看到生成的JavaScript代码和原先的一样。 TypeScript里的类只是JavaScript里常用的基于原型面向对象编程的简写。

ts同样也具有多态特性:

class Shape{
    area:number //如果想要子类用不了,就用private修饰
    protected color:string //子类可以用

    constructor(color:string,width:number,height:number){
        this.area=width*height;
        this.color=color;
    }

    shoutout(){
        return "I'm "+this.color+" with an area of "+this.area+" cm squared."
    }

}

class Square extends Shape{
    constructor(color:string,side:number){
        super(color,side,side);
        console.log(this.color)
    }
    // 覆盖了父类的方法,子类调用的是汉化的shoutout方法
    shoutout(){
        return "我是"+this.color+",面积为"+this.area+"平方厘米。"
    }
}

const square=new Square('red',2);
console.log(square.shoutout()) //我是red,面积为4平方厘米。

2.5 修饰符

修饰符的使用——上面的代码也可这么写:

class Shape{

    constructor(protected color:string,private width:number,private height:number){
    }

    // 读取area时,执行的事情。
    get area(){
        console.log('面积被读取了!')
        return this.width*this.height;
    }

    shoutout(){
        return "I'm "+this.color+" with an area of "+this.area+" cm squared."
    }

}

class Square extends Shape{
    constructor(color:string,side:number){
        super(color,side,side);
        console.log(this.color)
    }
    // 覆盖了父类的方法,子类调用的是汉化的shoutout方法
    shoutout(){
        return "我是"+this.color+",面积为"+this.area+"平方厘米。"
    }
}

const square=new Square('red',2);
console.log(square.shoutout()) 
// red
// 面积被读取了!
// 我是red,面积为4平方厘米。

area就成了计算属性。

2.6 泛型

泛型就是说,在定义函数,接口或类的时候,不预先指定类型,而是等到使用时才?️。

具体应用见第三章。

3. 在vue中使用ts

创建项目时,执行

vue create vue-ts

接下来会有一段默认选项,可按照以下配置

  • 自定义(Manually select feature)
  • 添加ts支持:Typescript
  • 基于类的组件(y)
  • tslint

创建好项目之后发现整个应用都怪怪的:

执行:

npm run serve

即可编译查看。

3.1 项目变化

在根目录下,多了一个 tslint.json,这是对编程偏好的设置。

还多了一个 tsconfig.json:它反映的是项目需要编译那个js版本,哪些库,编译目录等。

页面

Home.vue中:

<template>
  <div class="home">
    <img alt="Vue logo" src="../assets/logo.png">
    <HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src

@Component({
  components: {
    HelloWorld,
  },
})
export default class Home extends Vue {}
</script>

主要变化的还是script部分的编码:

结尾需要声明一个类,说明继承于vue:

export default class Home extends Vue {}

开头声明组件,需要一个装饰器 @

@Component({
  components: {
    HelloWorld,
  },
})

由此可见,component下面的都是配置文件。

装饰器 @就是一个工厂函数。

你也可以这么写:

@Component({
  props:{
    name:{
      tyoe:String,
      default:'djtao'
    }
  }
})
组件

在组件 Helloworld.vue中:

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component
export default class HelloWorld extends Vue {
  @Prop() private msg!: string;
}
</script>

@Prop()privatemsg!:string;表示: msg的类型必须存在(!)且必须是字符串,而且为 Helloworld私有。

3.2 用ts写页面

父组件给的属性(prop)

创建一个 Hello.vue组件,

在Home.vue中导入Hello:

<template>
  <div class="home">
    <Hello msg="hello"/>
  </div>
</template>

import Hello from '@/components/Hello.vue';

在hello里这么写:

<template>
  <div>{{msg}}</div>
</template>

<script lang="ts">
    import {Component,Prop,Vue} from 'vue-property-decorator';

    @Component
    export default class Hello extends Vue {
         @Prop({required:true}) private msg!:string;
    }
</script>

写到这里,命令行里已经报很多警告了。但没报错就先不管。

msg!表示告诉编译器,父类会传属性。但实际上不会报错。而 ({required:true})表示告诉vue,必须检验这个值是否存在。因此二者必须一起写。

一般数据(data)

传统的data应该怎么写?直接写。

export default class Hello extends Vue {
  @Prop({ required: true }) private msg!: string;
  featrues = ['类型注释', '函数'];
}

引起异常的舒适。

定义方法(methods)

现在要给hello加点功能:

<template>
  <div>
      <input type="text" @keyup.enter="addFeatrue($event)">
      <ul v-for="featrue in featrues" :key="featrue.index">
          <li>{{featrue}}</li>
      </ul>
  </div>
</template>

直接在component配置写方法就行了:

<script lang="ts">
import { Component, Prop, Vue } from "vue-property-decorator";

@Component
export default class Hello extends Vue {
  @Prop({ required: true }) private msg!: string;
      featrues = ['类型注释', 'balabala'];
      addFeatrue(e:any){
      this.featrues.push(e.target.value);
      e.target.value='';
  }
}
</script>

实现是异常简单。

组件数据的访问

目前这个组件根本没有定义数据是私有或是共有

所有的属性都包括hello里面,对此

  • 如果要让继承的类访问,可使用 protected
  • 如果想要都被访问到:用 public
  • 只读:readonly
计算属性

在hello.vue页面中需要一个计算属性。比如说features的条数

// 计算属性
  get count(){
      return this.featrues.length;
  }
created生命周期
private created(){
      window.setTimeout(()=>{
          this.featrues.push('aaa')
      },2000)
  }

简单到无话可说。

规范接口返回数据
interface Featrue{
    id:number,
    name:string,
    version:string
}

那么:

featrues:Featrue[]=[{id:1,name:'功能',version:'1'}, ...];
泛型

定义泛型Result:

interface Result<T> {
  ok:0|1,
  data:T[]
}

使用泛型约束接口返回的类型。

function getData<T>():Result<T> {
      const data:any[]=[
          {id:1,name:'类型注释',version:'1.0'}, {id:2,name:'bala',version:'1.0'}
      ]
      return {ok:1,data}
  }

使用时:

private created() {
      this.featrues=getData<Featrue>().data;
  }

在这里调用类似匿名类型的T作为别名。掉接口后,明确泛型为 <result>

事件装饰器

子组件派发事件给父组件,通常是用 emit。在ts'中,为 @Emit(需要导入)

// 通知老爹要发生addFeatrue事件
    @Emit
  private addFeatrue(e,any){
      this.featrues.push({id:this.featrues.length,name:e.target.value,version:'1.0'});
      e.target.value='';
  }

    // 父组件
    <Hello @add-featrue="onAddFeatrue">
监听(watch)
@Watch('msg',{deep:true});
onChange(val:string,oldVal:string){
  // do sth
}

本文分享自微信公众号 - 一Li小麦(gh_c88159ec1309),作者:一li小麦

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-05-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • typescript基础篇(5):类

    ts的类基本包括了es6+中类的全部功能。假如我要声明一条“狗”类,在ts中实现一个类是这样的:

    一粒小麦
  • 爬虫爬取豆瓣电影top250

    我想,爬虫对很多人来说是一个很有魅力的话题,它意味着不用什么努力就拿到了别人辛苦付出的的劳动成果。

    一粒小麦
  • typescript基础篇(6):泛型

    软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,在定义函数,接口或类的时候,...

    一粒小麦
  • 深入剖析 linux GCC 4.4 的 STL String

    gcc version 4.4.6 20110731 (Red Hat 4.4.6-3) (GCC)

    程序员小王
  • SAP Spartacus OccEndpointsService单元测试的依赖注入

    SiteContextConfig的实现:urlParameter,字符串数组和上下文名称:

    Jerry Wang
  • ASP.NET WebAPI 测试文档 (Swagger)

    SwaggerUI是一个简单的Restful API测试和文档工具。简单、漂亮、易用(官方demo)。通过读取JSON配置显示API .项目本身仅仅也只依赖一些...

    HueiFeng
  • 在服务端发起一个Post请求

    1.http://www.tuling123.com/openapi/api?key=9d2ff29d44b54e55acadbf5643569584&info...

    用户1055830
  • PDO::quote讲解

    PDO::quote — 为SQL语句中的字符串添加引号。(PHP 5 = 5.1.0, PECL pdo = 0.2.1)

    砸漏
  • react-native组建wechat

    IT故事会
  • 两条命令助你成为优秀的 YAML 工程师

    我们在编写 Kubernetes 资源清单的时候可能会经常会忘记要创建的资源名称,即使知道了可能也不记得该资源对象有哪些属性可以使用了,特别是对于那些名称很长的...

    我是阳明

扫码关注云+社区

领取腾讯云代金券