TypeScript
什么是 TypeScript
- JavaScript 超集
- 反对 ECMAScript6 规范,并反对输入 ECMAScript 3/5
JavaScript 与 TypeScript 的区别
TypeScript 是 JavaScript 的超集,扩大了 JavaScript 的语法,因而现有的 JavaScript 代码可与 TypeScript 一起工作无需任何批改,TypeScript 通过类型注解提供编译时的动态类型查看
装置 typescript
npm install -g typescript
tsc app.ts
或者在线 typescript 编译网站:
TypeScript Playground
根底数据类型
- 布尔类型
let bool: boolean = false;
// js
let bool = false;
- 数字
let num: number = 6
// js
let num = 6
- 字符串
let str: string = 'string'
// js
let str = 'string'
- 数组
let list: number[] = [1, 2, 3];
// js
let list = [1, 2, 3];
- 元组 Tuple
let x: [string, number] = ['hello', 6]
// js
let x = ['hello', 6];
- 枚举 enum
enum Direction {
NORTH
SOUTH
EAST
WEST
}
// js
var 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");
}
// js
function hello() {alert("Hello Runoob");
}
- null
示意对象值缺失。
let n: null = null;
- undefined
let u: undefined = undefined;
默认状况下 null
和undefined
是所有类型的子类型。就是说你能够把 null
和 undefined
赋值给 number
类型的变量。然而,当你指定了 --strictNullChecks
标记,null
和 undefined
只能赋值给 void
和它们各自。
- never
never
类型示意的是那些永不存在的值的类型。例如,never
类型是那些总是会抛出异样或基本就不会有返回值的函数表达式或箭头函数表达式的返回值类型;变量也可能是 never
类型,当它们被永不为真的类型爱护所束缚时。
// 返回 never 的函数必须存在无奈达到的起点
function error(message: string): never {throw new Error(message);
}
// 推断的返回值类型为 never
function fail() {return error("Something failed");
}
// 返回 never 的函数必须存在无奈达到的起点
function infiniteLoop(): never {while (true) {}}
- Object
object
示意非原始类型,也就是除 number
,string
,boolean
,symbol
,null
或undefined
之外的类型。
应用 object
类型,就能够更好的示意像 Object.create
这样的 API。例如:
declare function create(o: object | null): void;
create({prop: 0}); // OK
create(null); // OK
TypeScript 断言
类型断言有 2 种模式
- “尖括号”语法
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
- 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(); // okay
pet.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 function
function test() {}
// Anonymous function
let 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
属性时,咱们认为它是可迭代的。一些内置的类型如 Array
,Map
,Set
,String
,Int32Array
,Uint32Array
等都曾经实现了各自的 Symbol.iterator
。对象上的 Symbol.iterator
函数负责返回供迭代的值。
装璜器
Mixins
参考资料
- 1.2W 字 | 了不起的 TypeScript 入门教程
- TypeScript 夜点心:自定义类型守卫