TypeScript一文全
本笔记写于Evernote,自动同步到Postach.io博客中,由于博客可能会丢失排版格式等信息,有需要请点击以下链接 阅读原文(手机用户推荐)
安装nodejs(npm)
$tsc Runoob.ts 编译
$node Runoob.js 执行
你可以使用分号或不使用,建议使用,若写在同一行则一定需要使用分号来分隔
数据类型
any 声明为 any 的变量可以赋予任意类型的值
number 双精度 64 位浮点值,没有专门的整数类型
string
boolean
[ ]或Array<> 数组
[string, number] 元组:已知元素数量和类型的数组,各元素的类型不必相同,对应位置的类型需要相同
enum 如果enum的某个属性的值是计算出来的,那么它后面一位的成员必须要初始化值
void 用于标识方法返回值的类型,表示该方法没有返回值
null 表示对象值缺失。null 和 undefined 是其他任何类型(包括 void)的子类型,可以赋值给其它类型
undefined 用于初始化变量为一个未定义的值
never never 是其它类型(包括 null 和 undefined)的子类型,never 类型的变量只能被 never 类型所赋值,代表从不会出现的值
在TypeScript中启用严格的空校验(--strictNullChecks)特性,就可以使得null 和 undefined 只能被赋值给 void 或本身对应的类型
如果一个类型可能出现 null 或 undefined, 可以用 | 来支持多种类型,如果不这么做,下面只有x = 1能运行正确
// 启用 --strictNullChecks
let x: number | null | undefined;
x = 1; // 运行正确
x = undefined; // 运行正确
x = null; // 运行正确
never通常表现为抛出异常或无法执行到终止点(例如无限循环)
// 运行正确,never 类型可以赋值给 数字类型
y = (()=>{ throw new Error('exception')})();
// 返回值为 never 的函数可以是抛出异常的情况
function error(message: string): never {
throw new Error(message);
}
// 返回值为 never 的函数可以是无法被执行到的终止点的情况
function loop(): never {
while (true) {}
}
变量声明
let/var/const 变量名 : [类型] = [值]; // 没有设置类型会进行推断,没有设置初始值会默认为undefined
尽量用let代替var,因为var声明可以在包含它的函数、模块、命名空间或全局作用域内部任何位置被访问(没有局部域)
而当用let声明一个变量,它使用的是词法作用域或块作用域。 不同于使用var声明的变量那样可以在包含它们的函数外访问,块作用域变量在包含它们的块之外是不能访问的。
拥有块级作用域的变量的另一个特点是,它们不能在被声明之前读或写。 虽然这些变量始终"存在"于它们的作用域里,但在直到声明它的代码之前的区域都属于暂时性死区。 它只是用来说明我们不能在let语句之前访问它们,幸运的是TypeScript可以告诉我们这些信息。
使用var声明时,它不在乎你声明多少次;你只会得到1个
而let,则要求你不能在1个作用域里重复声明变量
在一个嵌套作用域里引入一个新名字的行为称做屏蔽,如内层循环的 i 可以屏蔽掉外层循环的 i
每次进入一个作用域时,它创建了一个变量的环境。 就算作用域内代码已经执行完毕,这个环境与其捕获的变量依然存在
const引用的值是不可变的。实际上const变量的内部状态是可修改的。幸运的是,TypeScript允许你将对象的成员设置成只读的
类型断言
var str2:number = str
值 as 类型
类型推断
当类型没有给出时,TypeScript 编译器利用类型推断来推断类型。 var num = 2; // 类型推断为 number
如果由于缺乏声明而不能推断出类型,那么它的类型被视作默认的动态 any 类型。
变量作用域
全局域:程序结构外部,可在代码的任何地方使用 var global_num=12;
类域:又称字段,可以是静态的类变量 num_val=13; static sval=10;
局部域:代码块中使用 var local_num=14;
运算符
比较接近c++,除法是真除法,逻辑运算符用&& || !
类型运算符 typeof 和 instanceof
console.log(typeof num); // 输出结果: number
+ 可用于字符串连接
语句
if-else if-else:
if(boolean_expression){
# 在布尔表达式 boolean_expression 为 true 执行
}else{
# 在布尔表达式 boolean_expression 为 false 执行
}
switch-case:
switch(expression){
case constant-expression :
statement(s); break; /* 可选的 */
default : /* 可选的 */
statement(s); }
for:
for (init; condition; increment ){
statement(s);}
for (var val in list) {
//语句 }
var j:any;
var n:any = "a b c"
for(j in n) {
console.log(n[j]) } // for..in只是下标迭代
for...of迭代器迭代
let someArray = [1, "string", false];
for (let entry of someArray) {
console.log(entry); // 1, "string", false }
forEach、every 和 some 是 JavaScript 的循环语法
let list = [4, 5, 6];
list.forEach((val, idx, array) => { // val: 当前值 // idx:当前index // array: Array }); // 在迭代过程中无法返回
list.every((val, idx, array) => { // val: 当前值 // idx:当前index // array: Array // 在迭代过程中可以返回
return true; // Continues // Return false will quit the iteration });
while()
do{ }while()
continue;
函数
函数-参数-默认参数-?可选参数-...剩余参数[]-返回值
function function_name( param[:datatype], defaultParam[:type] = default_value, optionalParam[?:type], ...restOfName: string[]):return_type {
// 语句
return value;
}
对象和数组是通过引用传递的。像数字、字符串、 bool 值这样的原始值是按值传递的。对对象的引用也是一种原始类型,和其他原始类型一样按值传递,但它所引用的对象仍然是按引用传递的。
匿名函数,可以将没有函数名的函数赋值给一个变量,这种表达式就成为函数表达式。而且其可以不声明返回值类型直接返回
var res = function( [arguments]) { ... return res; }
匿名函数也可以自调用,在声明的函数体后使用()即可
(function (){...})()
构造函数,是JS的定义函数方式,函数体可以写字符串
var res = new Function ([arg1[, arg2[, ...argN]],] functionBody)
var myFunction = new Function("a", "b", "return a * b");
lambda函数
( [param1, parma2,…param n] )=>statement; // =>箭头省略了函数声明的冗杂语句
var foo = x:number=>10 + x // lambda也可以多行 { }
重载函数
定义函数重载需要定义重载签名和实现签名
重载签名定义函数的形参和返回类型,没有函数体。一个函数可以有多个重载签名
// 定义重载签名
function greet(person: string): string;
function greet(persons: string[]): string[];
// 定义实现签名function greet(person: unknown): unknown {
if (typeof person === 'string') {
return `Hello, ${person}!`;
} else if (Array.isArray(person)) {
return person.map(name => `Hello, ${name}!`);
}
throw new Error('Unable to greet');}
Number对象
var num = new Number(value); Number 对象是原始数值的包装对象
console.log(num) // 输出 [Number: 10]
注意: 如果一个参数值不能转换为一个数字将返回 NaN (非数字值)
MAX_VALUE | 可表示的最大的数,MAX_VALUE 属性值接近于 1.79E+308。大于 MAX_VALUE 的值代表 "Infinity"。 |
MIN_VALUE | 可表示的最小的数,即最接近 0 的正数 (实际上不会变成 0)。最大的负数是 -MIN_VALUE,MIN_VALUE 的值约为 5e-324。小于 MIN_VALUE ("underflow values") 的值将会转换为 0。 |
NaN | 非数字值(Not-A-Number)。 |
NEGATIVE_INFINITY | 负无穷大,溢出时返回该值。该值小于 MIN_VALUE。 |
POSITIVE_INFINITY | 正无穷大,溢出时返回该值。该值大于 MAX_VALUE。 |
prototype | Number 对象的静态属性。使您有能力向对象添加属性和方法。"动态注入" |
constructor | 返回对创建此对象的 Number 函数的引用。 |
toFixed(digit) | 把数字转换为字符串,并对小数点指定位数。 |
toPrecision(d) | 把数字格式化为指定的长度。 |
toString() | 把数字转换为字符串,使用指定的基数。数字的基数是 2 ~ 36 之间的整数。若省略该参数则为十进制。 |
valueOf() | 返回一个 Number 对象的原始数字值。 |
String 对象
var txt = "string";
var txt = new String("string"); // 两者的区别是,String对象是对字符串值封装的对象
属性与方法:
constructor | 对创建该对象的函数的引用。 |
length | 返回字符串的长度。 |
prototype | 允许您向对象添加属性和方法。 |
charAt() | 返回在指定位置的字符。 |
charCodeAt() | 返回在指定的位置的字符的 Unicode 编码。 |
concat() | 连接两个或更多字符串,并返回新的字符串。 |
indexOf() | 返回某个指定的字符串值在字符串中首次出现的位置。 |
lastIndexOf() | 从后向前搜索字符串,并从起始位置(0)开始计算返回字符串最后出现的位置。 |
match() | 查找找到一个或多个正则表达式的匹配。 |
replace() | 替换与正则表达式匹配的子串 |
search() | 检索与正则表达式相匹配的值 |
slice() | 提取字符串的片断,并在新的字符串中返回被提取的部分 |
split() | 把字符串分割为子字符串数组。 |
substr() | 从起始索引号提取字符串中指定数目的字符 |
substring() | 提取字符串中两个指定的索引号之间的字符 |
toString() | valueOf() |
toLowerCase() | toUpperCase() |
模板字符串
可以定义多行文本和内嵌表达式。这种字符串是被`反引号`包围的,并且以${ expr }这种形式嵌入表达式
`Hello, my name is ${ name }.
I'll be ${ age + 1 } years old next month.`
Array 对象
var nums:number[] = [1,2,3,4]
var nums:number[] = new Array(4) // 构造函数可以传入数组大小,也可以传入初始化列表
数组解构
var arr:number[] = [12,13]
var[x,y] = arr // 将数组的两个元素赋值给变量 x 和 y
多维数组
var multi:number[][] = [[1,2,3],[23,24,25]]
数组方法
concat() | 连接两个或更多的数组,并返回结果 |
every(func) | 检测数值元素的每个元素是否都符合条件 |
filter() | 检测数值元素,并返回符合条件所有元素的数组 |
forEach() | 数组每个元素都执行一次回调函数 |
indexOf()
/ lastIndexOf() | 搜索数组中的元素,并返回它所在的位置。
如果搜索不到,返回值 -1,代表没有此项。 |
join() | 把数组的所有元素放入一个字符串 |
map() | 通过指定函数处理数组的每个元素,并返回处理后的数组 |
pop() | 删除数组的最后一个元素并返回删除的元素 |
push() | 向数组的末尾添加一个或更多元素,并返回新的长度 |
reduce() | 将数组元素计算为一个值(从左到右) |
reverse() | 反转数组的元素顺序 |
shift() | 删除并返回数组的第一个元素 |
slice() | 选取数组的的一部分,并返回一个新数组 |
some() | 检测数组元素中是否有元素符合指定条件 |
sort() | |
splice() | 从数组中添加或删除元素 |
toString() | |
unshift() | 向数组的开头添加一个或更多元素,并返回新的长度 |
Map 对象
Map 对象保存键值对,并且能够记住键的原始插入顺序
任何值(对象或者原始值) 都可以作为一个键或一个值
let m = new Map();
用 new 关键字来创建 Map。初始化时可以以数组的格式来传入键值对
相关的函数与属性:
map.clear() – 移除 Map 对象的所有键/值对 。
map.set(k, v) – 设置键值对,返回该 Map 对象。
map.get(k) – 返回键对应的值,如果不存在,则返回 undefined。
map.has(k) – 返回一个布尔值,用于判断 Map 中是否包含键对应的值。
map.delete(k) – 删除 Map 中的元素,删除成功返回 true,失败返回 false。
map.size – 返回 Map 对象键/值对的数量。
map.keys() - 返回一个 Iterator 对象, 包含了 Map 对象中每个元素的键 。
map.values() – 返回一个新的Iterator对象,包含了Map对象中每个元素的值 。
for...of 迭代 map,每一次迭代返回 [key, value] 数组
// 迭代 Map 中的 key
for (let key of nameSiteMapping.keys()) {
console.log(key); }
// 迭代 Map 中的 value
for (let value of nameSiteMapping.values()) {
console.log(value); }
// 迭代 Map 中的 key => value
for (let entry of nameSiteMapping.entries()) {
console.log(entry[0], entry[1]); }
// 使用对象解析
for (let [key, value] of nameSiteMapping) {
console.log(key, value); }
元组
元组是已知元素数量和类型的数组
可以先声明一个空元组,然后再初始化
可以使用以下两个函数向元组添加新元素或者删除元素:
- push() 向元组添加元素,添加在最后面。
- pop() 从元组中移除元素(最后一个),并返回移除的元素。
联合类型
联合类型(Union Types)可以通过管道 | 将变量设置多种类型,赋值时可以根据设置的类型来赋值。
注意:只能赋值指定的类型,如果赋值其它类型就会报错。
var val:string|number
val = 12 // 正确
val = "Runoob" // 正确
val = true // 错误
也可以将联合类型作为函数参数使用:
function disp(name:string|string[]) {
if(typeof name == "string") { console.log(name) }
else {}}}
我们也可以将数组声明为联合类型:
var arr:number[]|string[]; // 只能是其中一种,而不能两者混合
接口
接口是一系列抽象方法的声明,是一些方法特征的集合
interface IPerson {
firstName:string, // 属性
lastName:string,
sayHi: ()=>string } // 方法
var customer:IPerson = {
firstName:"Tom",
lastName:"Hanks",
sayHi: ():string =>{return "Hi there"} }
接口中我们可以将数组的索引值和元素设置为不同类型,索引值可以是数字或字符串
interface ages {
[index:string]:number }
接口继承
接口继承就是说接口可以通过其他接口来扩展自己
interface Musician extends Person // 还可以多继承
类
class Car {
// 字段
engine:string;
// 构造函数
constructor(engine:string) {
this.engine = engine }
// 方法
disp():void {
console.log("发动机为 : "+this.engine) }
}
// 创建一个对象
var obj = new Car("XXSY1")
继承
class Circle extends Shape // 不支持多继承
子类不能继承父类的私有成员(方法和属性)和构造函数
方法重写
直接复写即可,不需要声明。用super来引用父类
doPrint():void {
super.doPrint() // 调用父类的函数
console.log("子类的 doPrint()方法。") }
static关键字
用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用
class StaticMem {
static num:number;
static disp():void { console.log("num 值为 "+ StaticMem.num) }
}
StaticMem.num = 12 // 初始化静态变量
StaticMem.disp() // 调用静态方法
instanceof 运算符
用于判断对象是否是指定的类型
bool = obj instanceof Person
访问控制修饰符
public
protected
private
实现接口
类可以实现接口,使用关键字 implements,并将 interest 字段作为类的属性使用
class AgriLoan implements ILoan {
interest:number
rebate:number
constructor(interest:number,rebate:number) { this.interest = interest this.rebate = rebate }
}
对象
对象是包含一组键值对的实例。 值可以是标量、函数、数组、对象等
var sites = {
key1: "value1", // 标量
key2: "value",
site1: function() { // 函数 },
site2:["content1", "content2"] //集合
}
添加成员:sites.sayHello = function(){ return "hello";}
对象也可以作为一个参数传递给函数
var sites = { site1:"Runoob", site2:"Google", };
var invokesites = function(obj: { site1:string, site2 :string }){
console.log("site1 :"+obj.site1) console.log("site2 :"+obj.site2) }
invokesites(sites)
鸭子类型(Duck Typing)
鸭子类型是动态类型的一种风格,是多态(polymorphism)的一种形式
在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定
在鸭子类型中,关注点在于对象的行为,能作什么;而不是关注对象所属的类型(比较像python的一切皆对象,对象都可以多态)
命名空间
namespace SomeNameSpaceName {
export interface ISomeInterfaceName { } // 允许在外部调用该接口
export class SomeClassName { } // 允许在外部调用该类
}
在另外一个命名空间调用语法格式为:
SomeNameSpaceName.SomeClassName;
如果一个命名空间在一个单独的 TypeScript 文件中,则应使用三斜杠 /// 引用它
/// SomeNameSpaceName FileName.ts" />
嵌套命名空间
命名空间支持嵌套,即你可以将命名空间定义在另外一个命名空间里头
模块
模块的设计理念是可以更换的组织代码
模块是在其自身的作用域里执行,并不是在全局作用域,这意味着定义在模块里面的变量、函数和类等在模块外部是不可见的,除非明确地使用 export 导出它们。类似地,我们必须通过 import 导入其他模块导出的变量、函数、类等。
两个模块之间的关系是通过在文件级别上使用 import 和 export 建立的。
模块使用模块加载器去导入其它的模块。 在运行时,模块加载器的作用是在执行此模块代码前去查找并执行这个模块的所有依赖。
// 文件名 : SomeInterface.ts
export interface SomeInterface { // 代码部分 }
// 另一个文件:
import someInterfaceRef = require("./SomeInterface");
声明文件
TypeScript 作为 JavaScript 的超集,在开发过程中不可避免要引用其他第三方的 JavaScript 的库。虽然通过直接引用可以调用库的类和方法,但是却无法使用TypeScript 诸如类型检查等特性功能。为了解决这个问题,可以做一个将这些库里的函数和方法体去掉后的,只保留导出类型声明,描述 JavaScript 库和模块信息的声明文件。通过引用这个声明文件,就可以借用 TypeScript 的各种特性来使用库文件了。
使用 declare 关键字来定义它的类型,帮助 TypeScript 判断我们传入的参数类型对不对 declare module Module_Name {}
声明文件以 .d.ts 为后缀 ///
我们做了个UE4蓝图导出ts声明文件的插件,供ts引用蓝图