文章首发于:github.com/USTB-musion…python
ts是拥有类型系统的js的超集,近年来很是火热。能够这么说,ts才是真正意义上的js。虽然ts的官方文档很是全面,可是对于原来没有接触过ts的同窗来讲,全篇通读下来须要耗掉很多时间,这篇文章旨在为尝试入门ts的同窗使用。react
本文将从如下几部分进行总结:c++
一个好的代码习惯是经常对本身写的代码进行小的重构,使得代码可维护性更强。可是对于不少线上运行的代码,代码测试覆盖率每每不是很高,有时候哪怕一个变量名的改动,都会牵一发而动全身。而对于使用ts编写的项目就不会有这种担忧。ts的静态检查特性会帮助找出代码中有错误的部分。git
js是一门动态弱类型解释语言,变量声明后能够改变类型,并且类型须要在运行时才能肯定。而ts的报错提示是在编译时,不是在运行时。因此使用ts带来的静态类型检查等特性将使得IDE的提示更加完善。github
当你接手一个有历史包袱的项目时,确定会头疼于文档和代码注释的缺失,而对于ts来讲,是能够作到代码即文档的,经过声明文件能够知道哪些字段的含义以及哪些字段是必填和选填的。举个简单例子,当封装一个button的组件时:数组
export interface ButtonProps {
style?: React.CSSProperties
className?: string
label?: React.ReactNode
type?: 'primary' | 'default' | 'search'
size?: 'sm' | 'md' | 'lg' | 'mini'
disabled?: boolean
title?: string
onClick?: ((e: React.MouseEvent<HTMLButtonElement>) => void)
}
复制代码
经过这些声明文件能够知道,当使用这个button文件时,style是一个可选值,表示一个能够自定义样式的style字段。type也是一个可选值,表示按钮的颜色类型,能够选择'primary','default','mini'其中的一种。disabled也是一个可选值,传入的值必须是boolean类型。因此就能够看出类型声明自己就是很是好的文档。bash
强类型语言: 强类型语言不容许改变变量的数据类型,除非进行强制类型转换。函数
例如:若是定义了一个字符串变量str,若是没有进行强制类型转换,是把str不能看成布尔值,整型等非字符型进行处理的。c,c++,Java等都是强类型语言。性能
弱类型语言: 定义与强类型语言相反,一个变量能够被赋予不一样数据类型的值。测试
var a = '111';
var b = 222;
a = b;
console.log(a) // 222
复制代码
如以上的js代码所示,a是一个字符串变量,b是一个整型变量,可是却能够把b赋值给a,把a打印出来的值是222。
强类型的严谨性能有效地避免不少错误。
动态类型语言: 在执行阶段才作类型检查。
例如:js/python等就是属于动态类型语言,对类型检查很是宽松,bug可能隐藏好久才被发现。
静态类型语言: 在编译阶段就作类型检查
例如: c++/Java等属于静态类型语言,对类型检查很是严格,bug在编译阶段就会被发现。能作到代码即文档。
ES6的类型能够分为Boolean,Number,String,Array,Function,Object,Symbol,undefined,null。而TypeScript的数据类型则在ES6的基础上加上void,any,never,元组,枚举,高级类型。
基本语法
: type
TypeScript的基本类型语法是在变量以后使用冒号进行类型标识,这种语法也揭示了TypeScript的类型声明其实是可选的。
boolean是最基础的数据类型,在ts中,使用boolean来定义布尔值
let isDone: boolean = false;
复制代码
在ts中,使用number来定义数值类型
let num: number = 123
复制代码
在ts中,使用string来定义字符串类型
let name: string = 'jarod'
复制代码
在ts中,定义数组方式有两种: 一种是在能够在元素类型后面接上[],表示由此元素组成的一个数组:
let arr1: number[] = [1, 2, 3]
复制代码
还有一种是使用数组泛型,Array<元素类型> :
let arr2: Array<number> = [1, 2, 3]
复制代码
若是想在数组内表示不一样元素怎么办?这时候就须要使用元组类型了。元组类型容许表示一个已知元素数量和类型的数组,各元素的类型没必要相同。 好比,你能够定义一对值分别为number和string类型的元组。
let hello: [number, string] = [0, 'hello']
复制代码
enum类型是对JavaScript标准数据类型的一个补充。 像C#等其它语言同样,使用枚举类型能够为一组数值赋予友好的名字。
enum Month {
Jan,
Feb,
Mar
}
let month = [Month.Jan, Month.Feb, Month.Mar]
复制代码
若是一个函数永远没有返回值时,咱们能够声明其为void类型:
function example(): never {
throw new Error('never');
}
复制代码
any是ts的一个特殊类型,一旦声明为any,则意味着关闭来ts的类型检查,
let x: any = 0;
x = [];
x = false;
x = '';
复制代码
对于any类型的变量,能够赋予任何类型的值。使用any对迁移js的项目是很友好的。可是在真正开发中,尽可能仍是少用any为好。
在ts中,void表示函数没有返回值。
function example(): void {
console.log('this is void type');
}
复制代码
在TypeScript里,undefined和null二者各自有本身的类型分别叫作undefined和null。 和 void类似,它们的自己的类型用处不是很大:
let u: undefined = undefined;
let n: null = null;
复制代码
一些对象属性只能在对象刚刚建立的时候修改其值。 你能够在属性名前用 readonly来指定只读属性,在结合react使用的过程当中的例子:
interface Props {
readonly name: string;
}
interface State {
readonly color: string;
}
export class Child extends React.Component<Props,State> {
childMethod() {
this.props.name = 'jarod'; // ERROR: (props are immutable)
this.state.color = 'red'; // ERROR: (one should use this.setState)
}
}
复制代码
在 TypeScript 中,咱们使用接口(Interfaces)来定义对象的类型。
赋值的时候,变量的形状必须和接口的形状保持一致。
interface Name {
first: string;
second: string;
}
var personName:Name = {
first: '张三'
} // Property 'second' is missing in type '{ first: string; }' but required in type 'Name'
复制代码
ts会对每个字段作检查,若是没有对接口中声明的字段进行定义(非可选),能够看出,定义的变量比接口少一些属性则会抛出错误。
接口可以描述JavaScript中对象拥有的各类各样的外形。除了描述带有属性的普通对象外,接口也能够描述函数类型
interface Lib {
(): void;
version: string;
doSomething(): void;
}
function getLib() {
let lib = (() => {}) as Lib
lib.version = '1.0.0'
lib.doSomething = () => {}
return lib;
}
复制代码
function sum(x: number, y: number) {
return x + y
}
复制代码
let sum = (x: number, y: number): number => x + y
复制代码
对于参数,咱们能够声明其为可选参数,即在参数后面加"?"
function buildName(firstName: string, lastName?: string) {
// ...
}
复制代码
重载容许一个函数接受不一样数量或类型的参数时,做出不一样的处理。
function reverse(x: number): number;
function reverse(x: string): string;
function reverse(x: number | string): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
复制代码
抽象类只能在实例中使用,不能直接被实例化。
abstract class Animal {
eat() {
console.log('eat')
}
abstract sleep(): void
}
class Dog extends Animal {
constructor() {
super()
}
sleep() {
console.log('Dog sleep')
} // 在子类中实现父类中的抽象方法
}
复制代码
TypeScript 可使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected。
public 修饰的属性或方法是公有的,能够在任何地方被访问到,默认全部的属性和方法都是 public 的
class Animal {
public name;
public constructor(name) {
this.name = name;
}
}
let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
console.log(a.name); // Tom
复制代码
private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
class Animal {
private name;
public constructor(name) {
this.name = name;
}
}
let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
// index.ts(9,13): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
// index.ts(10,1): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
复制代码
protected 修饰的属性或方法是受保护的,它和 private 相似,区别是它在子类中也是容许被访问的
class Animal {
protected name;
public constructor(name) {
this.name = name;
}
}
class Cat extends Animal {
constructor(name) {
super(name);
console.log(this.name);
}
}
复制代码
定义:不预先肯定的数据类型,具体的类型须要在使用的时候才能肯定
例子: 声明一个打印函数,实现把传入的字符串打印出来:
function log(value: string): string {
console.log(value)
return value
}
复制代码
可是这时,加一个需求,要实现能把字符串数组也打印出来:
function log(value: string): string
function log(value: string[]): string[]
function log(value: any): {
console.log(value)
return value
}
复制代码
如上所示,能够用以前的函数重载来实现。
若是这时,再加一个需求,要实现能把任何类型的参数打印出来。泛型就派上用场了:
function log<T>(value: T): T {
console.log(value);
return value;
}
复制代码
软件工程中,咱们不只要建立一致的定义良好的API,同时也要考虑可重用性。组件不只可以支持当前的数据类型,同时也能支持将来的数据类型,这在建立大型系统时为你提供了十分灵活的功能。
Typescript实践中的进阶篇即将到来~