泛型

在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

我们需要一种方法使返回值的类型与传入参数的类型是相同的。 这里,我们使用了 类型变量,它是一种特殊的变量,只用于表示类型而不是值。

function identity<T>(arg: T): T {return arg;
}
复制代码

我们给identity添加了类型变量T。 T帮助我们捕获用户传入的类型(比如:number),之后我们就可以使用这个类型。 之后我们再次使用了 T当做返回值类型。现在我们可以知道参数类型与返回值类型是相同的了。 这允许我们跟踪函数里使用的类型的信息。

我们把这个版本的identity函数叫做泛型,因为它可以适用于多个类型。传入数值类型并返回数值类型。

声明泛型方法有以下两种方式:

function generics_func1<T>(arg: T): T {return arg;
}
// 或者
let generics_func2: <T>(arg: T) => T = function (arg) {return arg;
}
复制代码

我们定义了泛型函数后,可以用两种方法使用。

第一种是,传入所有的参数,包含类型参数:

let output = identity<string>("myString");  // type of output will be 'string'
复制代码

第二种方法更普遍。利用了类型推论 -- 可以省略类型参数,因为编译器会根据传入参数来自动识别对应的类型。

let output = identity("myString");  // type of output will be 'string'
复制代码

在方法一的方法体里,打印了arg参数的length属性。因为any可以代替任意类型,所以该方法在传入参数不是数组或者带有length属性对象时,会抛出异常。而方法二定义了参数类型是Array的泛型类型,肯定会有length属性,所以不会抛出异常。但是如果不加array或[]也没有length属性。

从下面这个例子可以看出,泛型类型相比较any类型来说,在某些情况下会带有类型本身的一些信息,而any类型则没有。

// 方法一:带有any参数的方法
function any_func(arg: any): any {console.log(arg.length);return arg;
}// 方法二:Array泛型方法
function array_func<T>(arg: Array<T>): Array<T> {console.log(arg.length);return arg;
}
复制代码

泛型类型

泛型接口

interface Generics_interface<T> {(arg: T): T;
}function func_demo<T>(arg: T): T {return arg;
}let func1: Generics_interface<number> = func_demo;
func1(123);     // 正确类型的实际参数
func1('123');   // 错误类型的实际参数(因为已经定义为number了)
复制代码

通过在接口上声明泛型,声明变量时明确指定泛型的具体类型,则赋值的方法将自动带上具体的类型约束。

泛型类型继承

interface LengthInterface {length: number;
}function func_demo<T extends LengthInterface>(arg: T): T {console.log(arg.length);return arg;
}func_demo({ a: 1, length: 2 });     // 含有length属性的对象
func_demo([1, 2]);                  // 数组类型
复制代码

上面的例子里,泛型类型继承自一个拥有length属性成员的接口,泛型类型将自动加上length属性的约束。调用时只有符合条件的对象才能正确赋值。

function copy<T extends U, U>(source: U, target: T): T {for (let prop in source) {target[prop] = source[prop];}return target;
}copy({ a: 1, b: 2 }, { a: 2, b: 3, c: 4 });         // 正确的实际参数
copy({ a: 1, b: 2 }, { q: 2, c: 4 });               // 错误的实际参数
复制代码

在上面的例子里,一个泛型类型继承自另外一个泛型类型。在方法调用时,就必须确保继承类型对应的参数对象属性完全包含被继承类型对应的参数对象。

泛型类

class Generics_Demo<T>{value: T;show(): T {return this.value;}
}let gene_demo1 = new Generics_Demo<number>();
gene_demo1.value = 1;
console.log(gene_demo1.show());                                     // 调用方法gene_demo1.show = function () { return gene_demo1.value + 1; }      // 赋值新方法,返回值类型必须是number
console.log(gene_demo1.show());
复制代码

通过指定明确类型的泛型类的实例,对属性赋值时,必须满足实际类型的约束。

枚举

数字枚举

enum Direction {Up = 1,Down,Left,Right
}
复制代码

如上,我们定义了一个数字枚举, Up使用初始化为 1。 其余的成员会从 1开始自动增长。换句话说, Direction.Up的值为 1, Down为 2, Left为 3, Right为 4如果不定义初始值的话就是从0开始。

使用枚举很简单:通过枚举的属性来访问枚举成员,和枚举的名字来访问枚举类型:

enum Response {No = 0,Yes = 1,
}function respond(recipient: string, message: Response): void {// ...
}respond("Princess Caroline", Response.Yes)
复制代码

下面的情况是不被允许的:

enum E {A = getSomeValue(),B, // error! 'A' is not constant-initialized, so 'B' needs an initializer
}
复制代码

字符串枚举

在一个字符串枚举里,每个成员都必须用字符串字面量,或另外一个字符串枚举成员进行初始化。

enum Direction {Up = "UP",Down = "DOWN",Left = "LEFT",Right = "RIGHT",
}
复制代码

由于字符串枚举没有自增长的行为,字符串枚举可以很好的序列化。 换句话说,如果你正在调试并且必须要读一个数字枚举的运行时的值,这个值通常是很难读的 - 它并不能表达有用的信息,字符串枚举允许你提供一个运行时有意义的并且可读的值,独立于枚举成员的名字。

异构枚举

enum BooleanLikeHeterogeneousEnum {No = 0,Yes = "YES",
}
复制代码

从技术的角度来说,枚举可以混合字符串和数字成员,但是我们不建议这样做

计算的和常量成员

当满足如下条件时,枚举成员被当作是常量:

1、它是枚举的第一个成员且没有初始化器,这种情况下它被赋予值 0:

// E.X is constant:
enum E { X }
复制代码

2、它不带有初始化器且它之前的枚举成员是一个 数字常量。 这种情况下,当前枚举成员的值为它上一个枚举成员的值加1。

// All enum members in 'E1' and 'E2' are constant.enum E1 { X, Y, Z }enum E2 {A = 1, B, C
}
复制代码

3、枚举成员使用 常量枚举表达式初始化。常数枚举表达式是TypeScript表达式的子集,它可以在编译阶段求值。当一个表达式满足下面条件之一时,它就是一个常量枚举表达式:

一个枚举表达式字面量(主要是字符串字面量或数字字面量)

一个对之前定义的常量枚举成员的引用(可以是在不同的枚举类型中定义的)

带括号的常量枚举表达式

一元运算符 +, -, ~其中之一应用在了常量枚举表达式

常量枚举表达式做为二元运算符 +, -, *, /, %, <<, >>, >>>, &, |, ^的操作对象。 若常数枚举表达式求值后为 NaN或Infinity,则会在编译阶段报错。

所有其它情况的枚举成员被当作是需要计算得出的值。

enum FileAccess {// constant membersNone,Read    = 1 << 1,Write   = 1 << 2,ReadWrite  = Read | Write,// computed memberG = "123".length
}
复制代码

类型推论

最佳通用类型

当需要从几个表达式中推断类型时候,例如

let x = [0, 1, null];
复制代码

为了推断x的类型,我们必须考虑所有元素的类型。 这里有两种选择: number和null。 计算通用类型算法会考虑所有的候选类型,并给出一个兼容所有候选类型的类型。

模块

模块的导入和导出

模块在其自身的作用域里执行,而不是在全局作用域里;

这意味着定义在一个模块里的变量,函数,类等等在模块外部是不可见的,除非你明确地使用export之一导出它们。

相反,如果想使用其它模块导出的变量,函数,类,接口等的时候,你必须要导入它们,可以使用import之一。

模块是自声明的。在TypeScript里,两个模块之间的关系是通过在文件级别上使用import和export建立的。下面是一个基本例子:

animal.ts

1 export class Animal {
2     name: string;
3     show(): string {
4         return this.name;
5     }
6 }
复制代码

app.ts

1 import {Animal} from './animal';
2 let dog = new Animal();
3 dog.name = '狗狗';
4 dog.show();
复制代码

上面的例子里,在animal.ts里声明了一个类Animal,通过export导出。在app.ts里,指定相对文件路径,通过import导入,就可以使用Animal类。

导入和导出的重命名

导入和导出时,通过as关键字对模块进行重命名。 animal.ts

class Animal {name: string;show(): string {return this.name;}
}export {Animal as ANI};
复制代码

app.ts

import {ANI as Animal} from './animal';
let dog = new Animal();
dog.name = '狗狗';
dog.show();
复制代码

导入和导出多个对象

MyLargeModule.ts

export class Dog { ... }
export class Cat { ... }
export class Tree { ... }
export class Flower { ... }
复制代码

Consumer.ts

import * as myLargeModule from "./MyLargeModule.ts";
let x = new myLargeModule.Dog();
复制代码

转载于:https://juejin.im/post/5cc10babf265da03587c0082

Typescript学习笔记(二)相关推荐

  1. Typescript 学习笔记七:泛型

    中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...

  2. Typescript 学习笔记一:介绍、安装、编译

    前言 整理了一下 Typescript 的学习笔记,方便后期遗忘某个知识点的时候,快速回忆. 为了避免凌乱,用 gitbook 结合 marketdown 整理的. github地址是:ts-gitb ...

  3. typeScript学习笔记day01——小肉包

    typeScript学习笔记 class1: 一.javaScript(js)的优缺点 javaScript是在微软公司和网景公司之间爆发的浏览器大战期间,由网景公司的Brendan Eich(布兰登 ...

  4. qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)

    原博主博客地址:http://blog.csdn.net/qq21497936 本文章博客地址:http://blog.csdn.net/qq21497936/article/details/7851 ...

  5. [转载]dorado学习笔记(二)

    原文地址:dorado学习笔记(二)作者:傻掛 ·isFirst, isLast在什么情况下使用?在遍历dataset的时候会用到 ·dorado执行的顺序,首先由jsp发送请求,调用相关的ViewM ...

  6. PyTorch学习笔记(二)——回归

    PyTorch学习笔记(二)--回归 本文主要是用PyTorch来实现一个简单的回归任务. 编辑器:spyder 1.引入相应的包及生成伪数据 import torch import torch.nn ...

  7. tensorflow学习笔记二——建立一个简单的神经网络拟合二次函数

    tensorflow学习笔记二--建立一个简单的神经网络 2016-09-23 16:04 2973人阅读 评论(2) 收藏 举报  分类: tensorflow(4)  目录(?)[+] 本笔记目的 ...

  8. Scapy学习笔记二

    Scapy学习笔记二 Scapy Sniffer的用法: http://blog.csdn.net/qwertyupoiuytr/article/details/54670489 Scapy Snif ...

  9. Ethernet/IP 学习笔记二

    Ethernet/IP 学习笔记二 原文链接:http://wiki.mbalib.com/wiki/Ethernet/IP 1.通信模式 不同于源/目的通信模式,EtherNet/IP 采用生产/消 ...

  10. TypeScript学习笔记3:运算符

    TS 和 JS 相对比的优势 TypeScript的安装步骤.运行问题及代码的简单运行 TypeScript学习笔记1:变量赋值及书写方式 TypeScript学习笔记2:数据类型 文章目录 运算符 ...

最新文章

  1. Python——pyiso8601
  2. Robotium中定位Android客户端疑难元素
  3. 计算机视觉方面代码和论文
  4. 配置库用户_GEE学习笔记 六十八:【GEE之Python版教程二】配置Python开发环境
  5. Spring Boot(5)---第一个Spring Boot应用程序
  6. 传统的主从复制的概念和要点
  7. GitHub 学习和使用
  8. python怎么做项目_通过例子说明如何维护好一个Python开源项目
  9. nagios常见错误及页面错误
  10. springboot 返回输出流_Spring Boot 静态资源处理,妙招
  11. 压缩包加密破解常见方法总结 CTF中Misc必备
  12. 阿里巴巴重要开源项目汇总(转载)
  13. editplus自动换行html,EditPlus如何自动换行
  14. C语言基础学习——基本数据类型(float型)
  15. 分享一个微信扫码连wifi项目
  16. sqldblink建好不能查询_眉山这个停车场显示有车位却不能停?原来是……
  17. Lazada开店步骤Lazada开店需要条件
  18. 【Stanford Online】Engineering: Algorithms1 NO.2 Asymptotic analysis
  19. xlinx芯片JTAG烧录
  20. Linux学习-49-列出进程调用或打开的文件信息(lsof命令)

热门文章

  1. 未来货运:无人驾驶技术和卡车司机如何配合?
  2. 史上最完整的人工智能书单大全,学习AI的请收藏好
  3. 因为在企业软件中采用了React,我差点被公司开除
  4. 关于VS的解决方案sln无法设置某些工程的依赖项的问题的解决方法
  5. 1.spring boot要求最低jdk1.8,平安默认1.6问题,-》安装JDK1.8 2.maven 3.3.3要求最低jdk1.7-安装jdk 1.8...
  6. 京东网络开放之路——自研交换机探索与实践
  7. 再和“面向对象”谈恋爱 - 对象简介(一)
  8. 【BZOJ】4032: [HEOI2015]最短不公共子串(LibreOJ #2123)
  9. 基于bmob的校园资料分享互助平台
  10. Werkzeug源码阅读笔记(四)