TypeScript - about

TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.
Any browser. Any host. Any OS. Open source.

ts 是 js类型的 超集,可以编译成js
ts 是属于Microsoft研发的

TypeScript INSTALL

npm install -g typescript

TypeScript COMPILE

tsc helloworld.ts //使用tsc 命令 自动编译成 helloworld.js

TypeScript 配置文件

tsc —init

  • 会会生成一份tsconfig.json,作用是将所有的ts转换为es5的js

TypeScript 批量编译(转换js)

  • tsc 回车,将当前目录下的所有ts文件,自动编译js,有多少份ts,就单独编译多少个js

  • vscode 可以安装一个插件搜索tsc关键字,插件名称’TypeScript Auto Compiler’ 效果和tsc命令一样的,只要将ts文件保存就会自动编译

TypeScript - 基本数据类型

number

和JavaScript一样,TypeScript里的所有数字都是浮点数。 这些浮点数的类型是 number。 除了支持十进制和十六进制字面量,TypeScript还支持ECMAScript 2015中引入的二进制和八进制字面量。

  1. let decLiteral: number = 6;
  2. let hexLiteral: number = 0xf00d;
  3. let binaryLiteral: number = 0b1010;
  4. let octalLiteral: number = 0o744;

例子:

  1. let num = 1;
  2. num = "2"; //报错
  3. num = 2.1;
  • num = “2”; 会报错,app.ts:2:1 - error TS2322: Type ‘“2”‘ is not assignable to type ‘number’.
  • 意思是app.ts 的第2行,第1个,有错误,不能将类型“”2””分配给类型“number”。
  • 不能存储非原有的类型数据
  • let num: number = 2; //ts原型

boolean

  1. let isDone: boolean = false;
  2. let isDone = 1; //报错
  3. isDone = true;
  • 不能将类型“”1””分配给类型“boolean”

string

  1. let name: string = `Gene`;
  2. name = 1; //报错
  • 不能将类型“”1””分配给类型“string”

any

有时候,我们会想要为那些在编程阶段还不清楚类型的变量指定一个类型。 不常用,如果常用的话和js的本质没有多大的意义

  1. let notSure;
  2. notSure = 4; //等同于let notSure: any = 4
  3. notSure = "hello";

Array

有两种方式可以定义数组。

  • 第一种,可以在元素类型后面接上[],表示由此类型元素组成的一个数组:
  1. let list: number[] = [1, 2, 3];
  • 第二种方式是使用数组泛型,Array<元素类型>:
  1. let list: Array<number> = [1, 2, 3];
  2. let listnumber[] =[1,2,3]; //等同于上面的写法
  3. let list2: Array<string> = ['tommy', 'hui', 'tom'];
  4. list2[0] = 1; // 报错
  5. list2 = 'lucky' // 报错
  6. list2 = [100] // 报错
  7. list2 = ['lucky'] // 在list2后面追加
  8. let notSureArr:any[] = ['tommy',1,false]
  • 不能将类型“”1””分配给类型“string”
  • 属于字符串,但不属于 string字符串数组
  • 属于number 数组

Tuple (元组)

元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为 string和number类型的元组

  1. // Declare a tuple type
  2. let x: [string, number];
  3. x = ['hello', 10]; // OK
  4. x = [10, 'hello']; // Error

enum (枚举)

使用枚举类型可以为一组数值赋予友好的名字。

  1. enum Color {
  2. Red,
  3. Green,
  4. Blue
  5. }
  6. let c: Color = Color.Green;

默认情况下,从0开始为元素编号。 你也可以手动的指定成员的数值。 例如,我们将上面的例子改成从 1开始编号:

  1. enum Color {
  2. Red = 1,
  3. Green,
  4. Blue
  5. }
  6. let c: Color = Color.Green;

console.log(c) // 2

function (函数)

返回值类型

在一个函数里面,可以设置返回值的类型

  1. function add(): number {
  2. return 22;
  3. }

空值

在一个函数里面,没有任何返回值

  1. function say(): void {
  2. console.log('hello');
  3. }

带参数的返回值

在参数里面如果没有定义数据类型,都是any类型,ts中最好就不要用any,否则ts没有意义了。
如果两个参数中其中一个不是数值,那么返回NaN

  1. function add(x: number, y: number): number {
  2. return x + y;
  3. }

函数类型

  1. let myFunc; // 相当于的这个函数的类型为,any
  2. myFunc(); // hello
  1. let myFunc: (a:number,b:number) => number // 相当于的这个函数(传参)的类型为number
  2. myFunc = say;
  3. myFunc(); //当定义了类型此时这里就会报错
  4. myFunc = add
  5. console.log(myFunc(1,1)) //2

object(对象)和type

简单对象类型

  1. let dataObj ={
  2. name:'tommy',
  3. age:18
  4. }
  5. dataObj = {};
  6. // 报错,空对象不符合,name为字符串,age为数字的类型;Type'{}' is missing the following properties from type '{name:string;age:number;}':name,age

当obj里面,有设置相应的键值对的参数,此时参数也是类型的一部分,ts会自动生成一个obj的格式,如下

  1. let dataObj:{name:string,age:number} ={
  2. name:'tommy',
  3. age:18
  4. }
  5. dataObj = {
  6. name: 'apple',
  7. age: 19
  8. }
  9. // 键名必须对应 name,age 否则也会报错

复杂对象类型

  1. // 参数一:数值数组
  2. // 参数二:对应的方法
  3. let complex:{data:number[],myfunc:(item:number) => number[] } = {
  4. data: [1,2,3],
  5. myfunc: function(item: number):number[] {
  6. this.data.push(item) // 传参追加
  7. return this.data
  8. }
  9. }

type 生成类型

当类型比较复杂的时候,为了后面便于修改和编写ts提供type生成类型

  1. type myType = {data:number[],myfunc:(item:number) => number[]}
  1. let complex2: myType = {
  2. data: [1,2,3],
  3. myfunc: function(item: number):number[] {
  4. this.data.push(item) // 传参追加
  5. return this.data
  6. }
  7. }

union type 可以对应选择类型

  1. let unionType : number | string | boolean = 10;
  2. unionType = '10';
  3. unionType = true;
  4. unionType = {} // 报错\

typeof检查类型

  1. let checkType = 10;
  2. if(typeof checkType == 'number'){
  3. console.log('number')
  4. }
  5. // 如果checkType = '12' 没有任何的打印了

判断类型的时候 必须使用’’\ “”引号引起来 不能==number

null 和 undefined

  1. let myNull = 11;
  2. myNull = null; // 报错

在ts模式下,会自动开启严格模式,myNull 属于number 就不能在赋值 null

  1. let myNull = null;
  2. myNull = nundefined;

never

  • never
    是任何类型(包括 null 和 undefined)的子类型,代表从不会出现的值。这意味着声明为 never 类型的变量只能被 never 类型所赋值,在函数中它通常表现为抛出异常无法执行到终止点(例如无线循环)
  1. let x: never;
  2. let y: number;
  3. // 运行错误,数字类型不能转为 never 类型
  4. x = 123;
  5. // 运行正确,never 类型可以赋值给 never类型
  6. x = (()=>{ throw new Error('exception')})();
  7. // 运行正确,never 类型可以赋值给 数字类型
  8. y = (()=>{ throw new Error('message')})();
  9. // 返回值为 never 的函数可以是抛出异常的情况
  10. function error(message: string): never {
  11. throw new Error(message);
  12. }
  13. // 死循环,返回值为 never 的函数可以是无法被执行到的终止点的情况
  14. function loop(): never {
  15. while (true) {}
  16. }

class 类(属性,方法)

  1. class Person {
  2. public name: string;
  3. protected gender: string;
  4. private age: number = 99;
  5. // 当你实例化一个对象 就会自动执行这个函数
  6. constructor(name: string,public usermane:string){
  7. this.name = name;
  8. this.username = usermane;
  9. }
  10. }

会提示name,gender变量没有初始化 那么我们要用到constructor

属性 描述
private(私有) 只能当前 可以使用
protected(被保护) 当前 或者 被继承的子类使用
public(公共) 当前 或者 子类类的外部
set 私有属性赋值
get 私有属性取值
static(静态属性) 设置静态属性,无需new
  1. class Person {
  2. public name: string;
  3. protected gender: string;
  4. private age: number = 99;
  5. // 当你实例化一个对象 就会自动执行这个函数
  6. constructor(name: string,gender:string,public usermane:string){
  7. this.name = name;
  8. this.usermane = usermane;
  9. this.gender = gender;
  10. }
  11. }
  12. const person = new Person('tommy','boy','tangmi');
  13. console.log(person.name,person.gender,person.usermane)
  14. // 报错 属性“gender”受保护,只能在类“Person”及其子类中访问。
  1. class Person {
  2. public name: string;
  3. protected gender: string;
  4. private age: number = 99;
  5. // 当你实例化一个对象 就会自动执行这个函数
  6. constructor(name: string,public usermane:string){
  7. this.name = name;
  8. this.usermane = usermane;
  9. }
  10. printAge(age:number){
  11. this.age = age;
  12. console.log(this.age);
  13. }
  14. setGender(gender:string){
  15. this.gender = gender;
  16. console.log(this.gender)
  17. }
  18. }
  19. const person = new Person('tommy','tangmi');
  20. console.log(person.name,person.usermane)
  21. person.printAge(9);
  22. person.setGender('boy');

class 类的继承

  1. // student 继承于 person类,并拥有public,protected的属性并可以使用,**private私有不能使用** 但可以显示出来
  2. class Student extends Person {
  3. constructor(name:string,username:string){
  4. super(name,username);
  5. console.log(this.gender); // 被保护,可以访问
  6. // console.log(this.age); // 私有的,不能访问
  7. }
  8. }
  9. const student = new Student('hello','hi');
  10. console.log(student.name,student.username)

class 修饰词set get

set get 用于隔离私有属性 和 可以公开属性

  1. class Person{
  2. private _name:string = 'tommy';
  3. // 私有属性赋值
  4. set setName(value: string){
  5. this._name = value;
  6. }
  7. // 私有属性取值
  8. get getName(){
  9. return this._name;
  10. }
  11. }
  12. let person = new Person();
  13. console.log(person.getName);
  14. person.setName = 'tangmi';
  15. console.log(person.getName);

class静态属性和方法

  1. class Person{
  2. static NO:number = 123;
  3. static setNo(value:number):number{
  4. return this.NO*value;
  5. }
  6. }
  7. console.log(Person.NO);
  8. console.log(Person.setNo(2));

namespace命名空间

  1. namespace Sum{
  2. export function sumMath(num1:number,num2:number):number{
  3. return num1 + num2;
  4. }
  5. export function timeMath(num1:number,num2:number):number{
  6. return num1 * num2;
  7. }
  8. }
  9. console.log(Sum.sumMath(1,5));

有点像组件化,和闭包~将多个方法放入一个整体,是需要namespace关键字 定义一个名词
必须配合 export 将方法导出给namespace,才能正常使用

namespace文件拆分

当代码量非常大的时候,namespace里面的方法也可以分开写,后续将多个ts合并成一个js文件
终端需要运行代码:tsc —outfile app.js summath.ts timemath.ts app.ts

  1. //summath.ts
  2. namespace Sum{
  3. export function sumMath(num1:number,num2:number):number{
  4. return num1 + num2;
  5. }
  6. }
  1. //timemath.ts
  2. namespace Sum{
  3. export function timeMath(num1:number,num2:number):number{
  4. return num1 * num2;
  5. }
  6. }
  1. //app.ts
  2. console.log(Sum.sumMath(1,5));
  3. console.log(Sum.timeMath(6,6));

namespace多重命名空间和引入文件

多重命名空间

  1. //summath.ts
  2. namespace Sum{
  3. export namespace Sumsum{
  4. export function sumMath(num1:number,num2:number):number{
  5. return num1 + num2;
  6. }
  7. }
  8. }
  1. //app.ts
  2. console.log(Sum.Sumsum.sumMath(1,5));

就是多套了一层namespace,当然要加上 export 导出才能正常使用,嗯哼~~

引入文件

  1. //app.ts
  2. ///<reference path='summath.ts' />
  3. ///<reference path='timemath.ts' />

终端需要运行代码:tsc app.ts —outFile app.js

等同于

终端需要运行代码:tsc —outfile app.js summath.ts timemath.ts app.ts

注意事项:

1.在ts文件里面,前头必须写/// 三条斜杠表示要引入的意思

2.终端需要运行代码outFile,F要大写

module的使用

将ts,js打包成为一个模块

  1. //summath.ts 将所有的变量和方法都要export 外部才能使用
  2. export function sumMath(num1:number,num2:number):number{
  3. return num1 + num2;
  4. }
  1. //app.ts
  2. import{sumMath} from './module/summath.ts'; //方法一
  3. console.log(sumMath(10,10));
  1. //app.ts
  2. import * as sum from './module/summath.ts'; //方法二
  3. console.log(sum.sumMath(10,10));
  • 接下来要将文件打包成模块,ts下有多种模式,常用commonjs,amd
  • commonjs规范——js没有模块系统,require是用来加载模块的,exports是暴露module模块中的内容

终端需要运行代码:tsc —module commonjs app.ts

此时浏览器会报错,exports is not defined ,因为浏览器(js)无法识别,exports,require

尝试使用amd模块,终端需要运行代码:tsc —module amd app.ts

此时浏览器会报错,define is not defined,因为浏览器(js)无法识别

  • 解决方法使用 baidu.com —> Bootcdn —> Systemjs 可以解析浏览可读的js
  • 使用0.21.5,使用0开头的版本,在title标签后再script引入,这个时候原本app.js不要引入了
  • 需要重新script标签里面的内容
  1. <script>
  2. System.config({
  3. baseUrl:'/' //app.js就在根目录下
  4. packges:{
  5. '/':{
  6. 'defaultExtension':'js'
  7. }
  8. }
  9. })
  10. System.import('app.js')
  11. </script>

interface接口

interface接口基本用法

  1. interface Person{
  2. name: string;
  3. age: number;
  4. say?:string;
  5. readonly dayoff: number;
  6. [propName: string] : any;
  7. greet():void;
  8. }
  9. // interface 可以继承,type不能继承
  10. // 在class类里面就用interface,不在类里面的type,interface 都能用
  11. // type Person2 = { name:string,age:number}
  12. let person:Person = {
  13. name:'tommy',
  14. age:28,
  15. // say:'hello'
  16. dayoff:2,
  17. hahah:10
  18. greet(){
  19. console.log('hi')
  20. }
  21. };
  22. // interface 定义的属性必须全部都全过来,否则会报错,如果不想传的话interface下的属性名+?
用法 描述
:号 必须要写
?: 可选的
readonly 只读,不能修改
[propName: string] 任何名+任何类型

interface接口 class 类的实现

  1. interface Person{
  2. name: string,
  3. age: number,
  4. say?:string,
  5. readonly dayoff:number,
  6. [propName: string]:any,
  7. greet():void;
  8. }
  9. class People implements Person{
  10. name: string = 'tangmi';
  11. age: number = 18 ;
  12. dayoff: number = 2;
  13. greet(){
  14. console.log('hihihihi');
  15. }
  16. }

interface接口继承

  1. interface Employee extends Person{
  2. }
  3. const employee: Employee = {
  4. name: 'tammy',
  5. age: 12,
  6. dayoff:2,
  7. greet(){
  8. console.log('employee');
  9. }
  10. }
  11. console.log(employee);

泛型 identity函数

指定类型 和 推断类型

  1. function identity<T>(arg: T): T {
  2. return arg;
  3. }
  4. console.log(identity<string>('10'));

指定类型通常简写,,TYPE 是可变动的,使用的时候再定义

推断类型 console.log(identity(‘10’));

在接口中使用泛型

  1. interface GenericIdentityFn {
  2. <T>(arg: T): T;
  3. }
  4. function identity<T>(arg: T): T {
  5. return arg;
  6. }
  7. let myIdentity: GenericIdentityFn = identity;

泛型约束

  1. function loggingIdentity<T>(arg: T): T {
  2. console.log(arg.length); // Error: T doesn't have .length
  3. return arg;
  4. }

相比于操作any所有类型,我们想要限制函数去处理任意带有.length属性的所有类型。 只要传入的类型有这个属性,我们就允许,就是说至少包含这一属性。 为此,我们需要列出对于T的约束要求。

创建一个包含 .length属性的接口,使用这个接口和extends关键字来实现约束:

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

现在这个泛型函数被定义了约束,因此它不再是适用于任意类型:

  1. loggingIdentity(3); // Error, number doesn't have a .length property

我们需要传入符合约束类型的值,必须包含必须的属性:

  1. loggingIdentity({length: 10, value: 3});

泛型里使用类

  1. class GenericNumber<T> {
  2. zeroValue: T;
  3. add: (x: T, y: T) => T;
  4. }
  5. let myGenericNumber = new GenericNumber<number>();
  6. myGenericNumber.zeroValue = 0;
  7. myGenericNumber.add = function(x, y) { return x + y; };
  8. console.log(myGenericNumber.add(10,10))