TypeScript
它是JavaScript的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程,支持ES6。
- 编译型语言:编译为 js 后运行,单独无法运行;
- 强类型语言;
- 面向对象的语言;
优势
- 类型系统实际上是最好的文档,大部分的函数看看类型的定义就可以知道如何使用;
- 可以在编译阶段就发现大部分错误,这总比在运行时候出错好;
- 增强了编辑器和 IDE 的功能,包括代码补全、接口提示、跳转到定义、重构等;
总结:TypeSctipt增加了代码的可读性和可维护性。
1.安装
npm install -g typescript
tsc -v
2.编译代码
tsc xxx.ts
生成xxx.js
3.数据类型
3.1 boolean number string
let name: type
3.2 Array
let list: number[] = [1, 2, 3];
//或
let list: Array<number> = [1, 2, 3];
3.3 元组 Tuple
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。
let x: [string, number];
x = ['hello', 10];
x = [10, 'hello'];
console.log(x[0].substr(1));
console.log(x[1].substr(1));
x[3] = 'world';
越界元素:当访问超出元组长度的元素时,它的类型会被限制为元祖中每个类型的联合类型
//测试时,IDE和编译都会报错,和文档不一致。
let arr:[string, number] = ['name', 20];
arr[0] = 'age';
arr[2] = 'string// 编译报错
arr[3] = 40;// 编译报错
arr[4] = true; // 编译报错
Type '"string"' is not assignable to type 'undefined'.
arr[2] = 'string';
Tuple type '[string, number]' of length '2' has no element at index '2'.
arr[2] = 'string';
3.4 枚举
enum
类型是对JavaScript标准数据类型的一个补充。
enum Color {Red, Green, Blue}
let c: Color = Color.Green
console.log(c)
let b:string=Color.Red
let a:number=Color.Blue
// 默认情况下,从0开始为元素编号。 你也可以手动的指定成员的数值。
// 手动赋值时, 未赋值的枚举成员会接着上一个枚举项递增(初始化)
enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green;
// 全部都采用手动赋值
enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green;
//值是number|string
enum Color {Red = '1', Green = true, Blue = 1}
//通过值取名字(*)
enum Color {Red = '1' Blue = 1}
let c:string=Color[2]
let d:string=Color[1]
let e:string=Color['1']
3.5 Any
不希望类型检查器对这些值进行检查而是直接让它们通过编译阶段的检查
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false;
与object类比,Any直接跳过类型检查,object允许赋值,但还是存在类型检查
let notSure: any = 4;
notSure.ifItExists(); // okay, ifItExists might exist at runtime
notSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check)
let prettySure: Object = 4;
prettySure.toFixed(); // Error: Property 'toFixed' doesn't exist on type 'Object'.
let list: any[] = [1, true, "free"];
list[1] = 100;
3.6 void
void
类型像是与any
类型相反,它表示没有任何类型。 当一个函数没有返回值时,你通常会见到其返回值类型是 void
function warnUser(): void {
console.log("This is my warning message");
}
void
类型的变量没有什么大用,因为你只能为它赋予undefined
和null
let unusable: void = undefined;
3.7 null、undefined
let u: undefined = undefined;
let n: null = null;
默认情况下null
和undefined
是所有类型的子类型。 就是说你可以把 null
和undefined
赋值给number
类型的变量。指定了--strictNullChecks
标记,null
和undefined
只能赋值给void
和它们各自
tsc [filename] --strictNullChecks
3.8 Never
never
类型表示的是那些永不存在的值的类型。 例如, never
类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 never
类型,当它们被永不为真的类型保护所约束时。
never
类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never
的子类型或可以赋值给never
类型(除了never
本身之外)。 即使 any
也不可以赋值给never
。
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {
}
}
3.9 Object
object
表示非原始类型,也就是除number
,string
,boolean
,symbol
,null
或undefined
之外的类型。
declare function create(o: object | null): void;
create({ prop: 0 }); // OK
create(null); // OK
create(42); // Error
create("string"); // Error
create(false); // Error
create(undefined); // Error
declare
declare 定义的类型只会用于编译时的检查,编译结果中会被删除。
https://www.runoob.com/typescript/ts-ambient.html
3.10 类型断言
有时候你会遇到这样的情况,你会比TypeScript更了解某个值的详细信息。 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。
通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript会假设你,程序员,已经进行了必须的检查。
//方式一
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
//方式二
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
4.变量声明
let、const、var、解构、展开(…),与js一致
5.接口
可以理解为一种规范或者约束,用来描述 对象(object) 的形状 或者对 类(class) 的行为 进行抽象。
4.1 接口定义
使用 interface 定义接口, 接口名称一般首字母大写,定义接口的时候,只定义声明即可,不包含具体内容;
实现接口的时候,要实现里面的内容,定义的变量比接口少了或多了属性都是不允许的;
类型检查器不会去检查属性的顺序,只要相应的属性存在并且类型也是对的就可以;
// 定义一个接口 Person
interface Person {
name: string;
age: number;
}
// 定义一个个变量,它的类型是 Person
let tom: Person = {
name: 'Tom',
age: 25
};
let tom: Person = {
name: 'tom'
}// 编译报错,少了age属性
let tom: Person = {
name: 'Tom',
age: 12,
sex:"男"
}// 编译报错,多了sex属性
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
// let myObj = {size: 10, label: "Size 10 Object"};
// printLabel({size: 10, label: "Size 10 Object"});
interface LabelledValue {
label: string;
[propName: string]: any;// 添加一个字符串索引签名,前提是你能够确定这个对象可能具有某些做为特殊用途使用的额外属性。
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
printLabel({size: 10, label: "Size 10 Object"});
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
printLabel({size: 10, label: "Size 10 Object"} as LabelledValue);
4.2 可选属性
使用 ? 代表可选属性, 即该属性可以不存在, 但不允许添加未定义的属性
interface Person {
name: string;
age?: number;
}
let tom: Person = {
name: 'tom'
}// age是可选属性
4.3 只读属性 readonly
对象属性只能在对象刚刚创建的时候修改其值。
interface Point {
readonly x: number;
readonly y: number;
}
let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!
只读的约束存在于第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候
let person: Person = {
id: 100,
name: 'tom',
}
person05.id = 90;
// => 编译报错:id为只读, 不可修改
let person2: Person = {
name: 'welson',
age: 2
}
// => 编译报错:给对象 person2 赋值,未定义只读属性id
person2.id = 1;
// => 编译报错:id为只读, 不可修改
TypeScript具有ReadonlyArray
类型,它与Array
相似,只是把所有可变方法去掉了,因此可以确保数组创建后再也不能被修改:
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!
4.4 额外的属性检查
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
// let myObj = {size: 10, label: "Size 10 Object"};
// printLabel(myObj);
// printLabel({size: 10, label: "Size 10 Object"});
interface LabelledValue {
label: string;
[propName: string]: any;// 添加一个字符串索引签名,表示LabelledValue可以有任意数量的属性。
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
printLabel({size: 10, label: "Size 10 Object"});
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
printLabel({size: 10, label: "Size 10 Object"} as LabelledValue);
propName: string]: string;
定义了任意属性,那么确定属性和可选属性都必须是它的子属性</