let decLiteral: number = 6; let hexLiteral: number = 0xf00d; // ES6 中的二进制表示法 let binaryLiteral: number = 0b1010; // ES6 中的八进制表示法 let octalLiteral: number = 0o744; let notANumber: number = NaN; let infinityNumber: number = Infinity;
编译结果
1 2 3 4 5 6 7 8
var decLiteral = 6; var hexLiteral = 0xf00d; // ES6 中的二进制表示法 var binaryLiteral = 10; // ES6 中的八进制表示法 var octalLiteral = 484; var notANumber = NaN; var infinityNumber = Infinity;
字符串
使用 string 定义字符串类型:
1 2 3 4 5 6
let myName: string = 'Tom'; let myAge: number = 25;
// 模板字符串 let sentence: string = `Hello, my name is ${myName}. I'll be ${myAge + 1} years old next month.`;
let tom: Person = { name: 'Tom', age: 25 }; 可选属性的含义是该属性可以不存在。
这时仍然不允许添加未定义的属性: interface Person { name: string; age?: number; }
let tom: Person = { name: 'Tom', age: 25, gender: 'male' };
// examples/playground/index.ts(9,5): error TS2322: Type '{ name: string; age: number; gender: string; }' is not assignable to type 'Person'. // Object literal may only specify known properties, and 'gender' does not exist in type 'Person'.
let tom: Person = { name: 'Tom', age: 25, gender: 'male' };
// index.ts(3,5): error TS2411: Property 'age' of type 'number' is not assignable to string index type 'string'. // index.ts(7,5): error TS2322: Type '{ [x: string]: string | number; name: string; age: number; gender: string; }' is not assignable to type 'Person'. // Index signatures are incompatible. // Type 'string | number' is not assignable to type 'string'. // Type 'number' is not assignable to type 'string'.
上例中,任意属性的值允许是 string,但是可选属性 age 的值却是 number,number 不是 string 的子属性,所以报错了。
我们可以在 TypeScript 中将变量定义为这些类型: let b: Boolean = newBoolean(1); let e: Error = newError('Error occurred'); let d: Date = newDate(); let r: RegExp = /[a-z]/;
DOM和BOM的内置对象
DOM 和 BOM 提供的内置对象有:
Document、HTMLElement、Event、NodeList 等。
1 2 3 4 5 6
TypeScript 中会经常用到这些类型: let body: HTMLElement = document.body; let allDiv: NodeList = document.querySelectorAll('div'); document.addEventListener('click', function(e: MouseEvent) { // Do something });
声明文件
进阶
类型别名
类型别名用来给一个类型起个新名字。
1 2 3 4 5 6 7 8 9 10 11
type Name = string; type NameResolver = () =>string; type NameOrResolver = Name | NameResolver; functiongetName(n: NameOrResolver): Name{ if (typeof n === 'string') { return n; } else { return n(); } } 类型别名常用于联合类型。
字符串字面量类型
字符串字面量类型用来约束取值只能是某几个字符串中的一个。
1 2 3 4 5 6 7 8 9 10
type EventNames = 'click' | 'scroll' | 'mousemove'; functionhandleEvent(ele: Element, event: EventNames) { // do something }
// index.ts(7,47): error TS2345: Argument of type '"dbclick"' is not assignable to parameter of type 'EventNames' 上例中,我们使用 type 定了一个字符串字面量类型 EventNames,它只能取三种字符串中的一种。
注意,类型别名与字符串字面量类型都是使用type进行定义。
元组
数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象
元组起源于函数编程语言,这些语言中会频繁使用元组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
简单的例子 定义一对值分别为 string 和 number 的元组: let tom: [string, number] = ['Tom', 25]; 当赋值或访问一个已知索引的元素时,会得到正确的类型: let tom: [string, number]; tom[0] = 'Tom'; tom[1] = 25;
tom[0].slice(1); tom[1].toFixed(2);
也可以只赋值其中一项: let tom: [string, number]; tom[0] = 'Tom';
但是当直接对元组类型的变量进行初始化或者赋值的时候,需要提供所有元组类型中指定的项。
1 2 3 4 5 6 7
let tom: [string, number]; tom = ['Tom', 25];
let tom: [string, number]; tom = ['Tom'];
// Property '1' is missing in type '[string]' but required in type '[string, number]'
越界的元素
当添加越界的元素时,它的类型会被限制为元组中每个类型的联合类型:
1 2 3 4 5 6
let tom: [string, number]; tom = ['Tom', 25]; tom.push('male'); tom.push(true);
// Argument of type 'true' is not assignable to parameter of type 'string | number'
let a = new Animal('Jack'); console.log(a.name); // Jack a.name = 'Tom';
// index.ts(9,13): error TS2341: Property 'name' is private and only accessible within class 'Animal'. // index.ts(10,1): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
// index.ts(11,17): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
而如果是用 protected 修饰,则允许在子类中访问:
1 2 3 4 5 6 7 8 9 10 11 12
class Animal{ protected name; publicconstructor(name){ this.name=name } } class Cat extends Animal{ constructor(name){ super(name) console.log(this.name) } }
当构造函数修饰为 private 时,该类不允许被继承或者实例化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
class Animal { public name; privateconstructor (name) { this.name = name; } } class Cat extends Animal { constructor (name) { super(name); } }
let a = new Animal('Jack');
// index.ts(7,19): TS2675: Cannot extend a class 'Animal'. Class constructor is marked as private. // index.ts(13,9): TS2673: Constructor of class 'Animal' is private and only accessible within the class declaration.
当构造函数修饰为 protected 时,该类只允许被继承:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
class Animal { public name; protectedconstructor (name) { this.name = name; } } class Cat extends Animal { constructor (name) { super(name); } }
let a = new Animal('Jack');
// index.ts(13,9): TS2674: Constructor of class 'Animal' is protected and only accessible within the class declaration.
修饰符还可以使用在构造函数参数中,等同于类中定义该属性,使代码更简洁。
1 2 3 4 5 6
class Animal { // public name: string; publicconstructor (public name) { this.name = name; } }
// index.ts(5,3): error TS2403: Subsequent variable declarations must have the same type. Variable 'price' must be of type 'number', but here has type 'string'.