TypeScript

什么是TypeScript

  • JavaScript超集
  • 反对ECMAScript6规范,并反对输入ECMAScript 3/5

JavaScript 与 TypeScript 的区别

TypeScript 是 JavaScript 的超集,扩大了 JavaScript 的语法,因而现有的 JavaScript 代码可与 TypeScript 一起工作无需任何批改,TypeScript 通过类型注解提供编译时的动态类型查看

装置typescript

npm install -g typescripttsc app.ts

或者在线typescript编译网站:

TypeScript Playground

根底数据类型

  • 布尔类型
let bool: boolean = false;// jslet bool = false;
  • 数字
let num: number = 6// jslet num = 6
  • 字符串
let str: string = 'string'// jslet str = 'string'
  • 数组
let list: number[] = [1, 2, 3];// jslet list = [1, 2, 3];
  • 元组 Tuple
let x: [string, number] = ['hello', 6]// jslet x = ['hello', 6];
  • 枚举 enum
enum Direction {    NORTH    SOUTH    EAST    WEST}// jsvar Direction;(function (Direction) {    Direction[Direction["NORTH"] = 0] = "NORTH";    Direction[Direction["SOUTH"] = 1] = "SOUTH";    Direction[Direction["EAST"] = 2] = "EAST";    Direction[Direction["WEST"] = 3] = "WEST";})(Direction || (Direction = {}));
  • any
let notSure: any = 4;
  • void

用于标识办法返回值的类型,示意该办法没有返回值。

function hello(): void {    alert("Hello Runoob");}// jsfunction hello() {    alert("Hello Runoob");}
  • null

示意对象值缺失。

let n: null = null;
  • undefined
let u: undefined = undefined;

默认状况下nullundefined是所有类型的子类型。 就是说你能够把 nullundefined赋值给number类型的变量。然而,当你指定了--strictNullChecks标记,nullundefined只能赋值给void和它们各自。

  • never

never类型示意的是那些永不存在的值的类型。 例如, never类型是那些总是会抛出异样或基本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 never类型,当它们被永不为真的类型爱护所束缚时。

// 返回never的函数必须存在无奈达到的起点function error(message: string): never {    throw new Error(message);}// 推断的返回值类型为neverfunction fail() {    return error("Something failed");}// 返回never的函数必须存在无奈达到的起点function infiniteLoop(): never {    while (true) {    }}
  • Object

object示意非原始类型,也就是除numberstringbooleansymbolnullundefined之外的类型。

应用object类型,就能够更好的示意像Object.create这样的API。例如:

declare function create(o: object | null): void;create({ prop: 0 }); // OKcreate(null); // OK

TypeScript断言

类型断言有2种模式

  1. “尖括号” 语法
let someValue: any = "this is a string";let strLength: number = (<string>someValue).length;
  1. as 语法
let someValue: any = "this is a string";let strLength: number = (someValue as string).length;

类型守卫

类型爱护是可执行运行时查看的一种表达式,用于确保该类型在肯定的范畴内。换句话说,类型爱护能够保障一个字符串是一个字符串,只管它的值也能够是一个数值。类型爱护与个性检测并不是齐全不同,其次要思维是尝试检测属性、办法或原型,以确定如何解决值。目前次要有四种的形式来实现类型爱护:

  • 属性判断: in
interface Foo {    foo: string;}interface Bar {    bar: string;}function test(input: Foo | Bar) {    if('foo' in input) {        // 这里 input 的类型「收紧」为 Foo    } else {        // 这里 input 的类型「收紧」为 Bar    }}
  • 类型判断: typeof
function test(input: string | number) {    if(typeof input == 'string') {        // 这里 input 的类型「收紧」为 string    } else {        // 这里 input 的类型「收紧」为 number    }}
  • 实例判断: instanceof
class Foo {};class Bar {};function test(input: Foo | Bar) {    if(input instanceof Foo) {        // 这里 input 的类型「收紧」为 Foo    } else {        // 这里 input 的类型「收紧」为 Bar    }}
  • 字面量相等判断 ==, !=, ===, !==
type Foo = 'foo' | 'bar' | 'unknown';function test(input: Foo) {  if (input != 'unknown') {    // 这里 input 的类型「收紧」为 'foo' | 'bar'  } else {    // 这里 input 的类型「收紧」为 'unknown'  }}

高级类型

1. 联结类型(Union Types)

代码库心愿传入 number或 string类型的参数,能够应用 联结类型做为 padding的参数:

/** * Takes a string and adds "padding" to the left. * If 'padding' is a string, then 'padding' is appended to the left side. * If 'padding' is a number, then that number of spaces is added to the left side. */function padLeft(value: string, padding: string | number) {    // ...}let indentedString = padLeft("Hello world", true); // errors during compilation

如果一个值是联结类型,咱们只能拜访此联结类型的所有类型里共有的成员。

interface Bird {    fly();    layEggs();}interface Fish {    swim();    layEggs();}function getSmallPet(): Fish | Bird {    // ...}let pet = getSmallPet();pet.layEggs(); // okaypet.swim();    // errors
  • 类型爱护与辨别类型
let pet = getSmallPet();if ((<Fish>pet).swim) {    (<Fish>pet).swim();}else {    (<Bird>pet).fly();}

类型别名

类型别名用来给一个类型起个新名字。

type Message = string | string[];let greet = (message: Message) => {  // ...};

穿插类型

穿插类型是将多个类型合并为一个类型。 这让咱们能够把现有的多种类型叠加到一起成为一种类型,它蕴含了所需的所有类型的个性。

function extend<T, U>(first: T, second: U): T & U {    let result = <T & U>{};    for (let id in first) {        (<any>result)[id] = (<any>first)[id];    }    for (let id in second) {        if (!result.hasOwnProperty(id)) {            (<any>result)[id] = (<any>second)[id];        }    }    return result;}class Person {    constructor(public name: string) { }}interface Loggable {    log(): void;}class ConsoleLogger implements Loggable {    log() {        // ...    }}var jim = extend(new Person("Jim"), new ConsoleLogger());var n = jim.name;jim.log();

函数

函数定义

// Named functionfunction test() {}// Anonymous functionlet test = function() {};

函数类型

function add(x: number, y: number): number {    return x + y;}let myAdd = function(x: number, y: number): number { return x + y; };

可选参数

编译器会校验传递给一个函数的参数个数必须与函数冀望的参数个数统一。

JavaScript里,每个参数都是可选的,可传可不传。 没传参的时候,它的值就是undefined。 在TypeScript里咱们能够在参数名旁应用 ?实现可选参数的性能。

function test(a: string, b?: string) {    if(b) {        return b    } else {        return a    }}

可选参数必须跟在必须参数前面。

默认参数

function buildName(firstName: string, lastName = "Smith") {    return firstName + " " + lastName;}let result1 = buildName("Bob");                  // works correctly now, returns "Bob Smith"

残余参数

必要参数,默认参数和可选参数有个共同点:它们示意某一个参数。 有时,你想同时操作多个参数,或者你并不知道会有多少参数传递进来。 在JavaScript里,你能够应用 arguments来拜访所有传入的参数。

function buildName(firstName: string, ...restOfName: string[]) {  return firstName + " " + restOfName.join(" ");}let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");

省略号也会在带有残余参数的函数类型定义上应用到:

function buildName(firstName: string, ...restOfName: string[]) {  return firstName + " " + restOfName.join(" ");}let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;

重载

数组

数据解构

let x: number; let y: number; let z: number;let five_array = [0,1,2,3,4];[x,y,z] = five_array;

数组开展运算符

let two_array = [0, 1];let five_array = [...two_array, 2, 3, 4];

数组遍历

接口

接口

interface IQuery {  page: number;  findOne(): void;  findAll(): void;}

可选属性

interface SquareConfig {  color?: string;  width?: number;}

只读属性

interface Point {    readonly x: number;    readonly y: number;}

readonly与const区别

最简略判断该用readonly还是const的办法是看要把它做为变量应用还是做为一个属性。 做为变量应用的话用 const,若做为属性则应用readonly

额定的属性查看

let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);

或者

interface SquareConfig {    color?: string;    width?: number;    [propName: string]: any;}

函数类型

除了用接口形容对象构造外,接口也能够形容函数类型。

interface SearchFunc {  (source: string, subString: string): boolean;}
let mySearch: SearchFunc;mySearch = function(source: string, subString: string) {  let result = source.search(subString);  return result > -1;}

泛型

软件工程中,咱们不仅要创立统一的定义良好的API,同时也要思考可重用性。 组件不仅可能反对以后的数据类型,同时也能反对将来的数据类型,这在创立大型零碎时为你提供了非常灵便的性能。

function identity<T>(arg: T): T {    return arg;}

应用形式

  • 第一种 传入所有的参数,蕴含类型参数
let output = identity<string>("myString");  // type of output will be 'string'
  • 第二种 类型推论 -- 即编译器会依据传入的参数主动地帮忙咱们确定T的类型
let output = identity("myString");  // type of output will be 'string'

泛型类

class GenericNumber<T> {    zeroValue: T;    add: (x: T, y: T) => T;}

泛型束缚

interface Lengthwise {    length: number;}function loggingIdentity<T extends Lengthwise>(arg: T): T {    console.log(arg.length);  // Now we know it has a .length property, so no more error    return arg;}

迭代器与生成器

可迭代性

当一个对象实现了Symbol.iterator属性时,咱们认为它是可迭代的。 一些内置的类型如 ArrayMapSetStringInt32ArrayUint32Array等都曾经实现了各自的Symbol.iterator。 对象上的 Symbol.iterator函数负责返回供迭代的值。

装璜器

Mixins

参考资料

  • 1.2W字 | 了不起的 TypeScript 入门教程
  • TypeScript 夜点心:自定义类型守卫