基础类型
string、number、boolean
array(数组)
ts 表示数组有两种形式,元素类型[]
或者 Array<元素类型>
,示例:
1 2
| let list: number[] = [1, 2, 3]; let list: Array<number> = [1, 2, 3];
|
如果是只读数组,被赋值后就不能修改了,使用ReadonlyArray<元素类型>
:
1
| let rolist: ReadonlyArray<number> = [1, 2, 3, 4, 5];
|
unknown
any
enum(枚举)
数字枚举
默认就是数字枚举,从 0 开始递增,如果给某个成员赋值,后面的在这个值的基础上自增。
1 2 3 4 5 6 7 8 9 10 11 12 13
| enum Direction { up, down, left, right, }
enum Direction { up, down = 2, left, right, }
|
字符串枚举
字符串枚举,因为不能自增,所以需要每个成员都进行初始化。
1 2 3 4 5 6
| enum Direction { up = "up", down = "down", left = "left", right = "right", }
|
异构枚举
混合字符串和数字,但是不推荐这么做。
1 2 3 4
| enum BooleanLikeHeterogeneousEnum { No = 0, Yes = "YES", }
|
外部枚举
void(空值)
null 和 undefined
当打印一个变量时,这个变量没有定义就是undefined
,定义了没有赋值就是null
。
ts 中,null
和undefined
各自有自己的类型,分别是 null 和 undefined,它们本身作用不大,默认情况下,null 和 undefined 类型是所有其他类型的子类型,就是说你可以把null
和undefined
赋值给number
类型的变量。
不过,指定–strictNullChecks,null
和undefined
就只能赋值给 any 和它们各自的类型(有一个例外是undefined
还可以赋值给 void 类型)
never
void
表示没有任何类型,never
表示永远不存在的值的类型。
void
没有返回值,never
返回的值没有类型。
object
类型断言
类型转换,有两种形式:
1 2 3 4 5 6 7
| 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;
|
在 TypeScript 里使用 JSX 时,只有 as 语法断言是被允许的。
关于 number、string、boolean、symbol、object
接口
接口的作用是规范、限制、约束。定义接口的关键字是 interface 和 type。
- interface 可以重复定义(merge),type 不可以
- interface 定义的接口格式固定,type 可以定义各种格式的接口
- interface 可以实现接口的 extends/implements,type 不行,基于此,推荐约束变量类型的时候用 type,定义类接口的时候用 interface
属性类接口
1 2 3 4 5 6 7 8
| interface LabeledValue { label: string; } function printLabel(labeledObj: LabeledValue) { console.log(labeledObj.label); } let myObj = { size: 10, label: "Size 10 Object" }; printLabel(myObj);
|
定义接口的关键字 interface 或者 type,上例还可以写作:
1 2 3
| type LabeledValue { label: string; }
|
可选属性 ?
接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| interface PaintOptions { shape: Shape; xPos?: number; yPos?: number; }
function paintShape(opts: PaintOptions) { }
const shape = getShape(); paintShape({ shape }); paintShape({ shape, xPos: 100 }); paintShape({ shape, yPos: 100 }); paintShape({ shape, xPos: 100, yPos: 100 });
|
xPos
和 yPos
均被视为可选
只读属性 readonly
一些对象属性在创建的时候定义其值,然后就再也不能被修改,这时候就可以在属性名前用 readonly 来指定只读属性:
1 2 3 4 5 6 7 8 9
| interface Point { readonly x: number; readonly y: number; }
let p1: Point = { x: 1, y: 2 }; let p2: Point = { x: 3, y: 4 };
|
只读数组的类型是ReadonlyArray<元素类型>
:
1 2 3 4 5 6
| let a: number[] = [1, 2, 3, 4]; let ro: ReadonlyArray<number> = a; ro[0] = 12; ro.push(5); ro.length = 100; a = ro;
|
readonly 和 const
最简单判断该用 readonly 还是 const 的方法是看要把它做为变量使用还是做为一个属性。 做为变量使用的话用 const ,若做为属性则使用 readonly 。
额外的属性检查
示例一,正常:
1 2 3 4 5 6 7 8
| interface LabeledValue { label: string; } function printLabel(labeledObj: LabeledValue) { console.log(labeledObj.label); } let myObj = { size: 10, label: "Size 10 Object" }; printLabel(myObj);
|
示例二,报错:
1 2 3 4 5 6 7
| interface LabeledValue { label: string; } function printLabel(labeledObj: LabeledValue) { console.log(labeledObj.label); } printLabel({ size: 10, label: "Size 10 Object" });
|
prinLabel 函数期待的参数是 LabeledValue 类型的,所以 size 属性显然是多余的,示例一中,定义变量 myObject 时没有指定类型,这么写可以绕开检查,最后没有报错,此外还有两种方式也可以绕开检查:
1 2
| printLabel({ size: 10, label: "Size 10 Object" } as LabeledValue);
|
1 2 3 4 5 6 7 8 9 10
| interface LabeledValue { label: string; [key: string]: any; } function printLabel(labeledObj: LabeledValue): void { console.log(labeledObj.label); console.log(labeledObl.size); } printLabel({ size: 100, label: "Size 10 Object" });
|
不提倡绕开检查,除非是包含方法和内部状态的复杂对象字面量,可能需要使用这些技巧。
函数类型接口
不常用
1 2 3 4 5 6 7 8 9 10
| type Fn = { (a: string, b: number): void; };
let fn: Fn = (x, y) => { console.log(x); console.log(y); };
fn("string", 2);
|
可索引接口
不常用,用于描述哪些能够”通过索引得到”的类型(数组和对象),比如 a[10]、b[“name”]
1 2 3 4 5 6 7
| type A = { [index: number]: string; };
let a: A = ["string1", "string2"]; console.log(a);
|
类类型接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| interface X { name: string; eat(food: string): string; }
class A implements X { public name: string; constructor(name: string) { this.name = name; } eat() { console.log(123); return "food"; } }
let a = new A("lujinkai"); a.eat();
|
接口继承接口
1 2 3 4 5 6 7 8 9 10 11
| interface A { name: string; }
interface B extends A { age: number; }
let b: B = { name: "lujinkai", age: 23 };
console.log(b);
|
接口继承类
接口不仅可以继承接口,还可以继承类。
示例:
1 2 3 4 5 6
| class Control { private state: any; } interface SelectableControl extends Control { select(): void; }
|
类静态部分和实例部分
ts 中,类分静态部分和实例部分,new 实例化对象后,对象中有的部分就是实例化的部分,对象中没有的部分就是静态部分,构造函数 constructor 就是静态部分。
类类型接口只检查实例部分,不检查静态部分,如果想要检查静态部分,可以使用类表达式。
示例:
1 2 3 4 5 6 7 8 9 10 11 12
| interface ClockConstructor { new (hour: number, minute: number): void; } interface ClockInterface { tick(): void; } const Clock: ClockConstructor = class Clock implements ClockInterface { constructor(h: number, m: number) {} tick() { console.log("beep beep"); } };
|
函数
TypeScript 为 JavaScript 函数添加了额外的功能,让我们可以更容易地使用。
可选参数
1 2 3 4
| function buildName(firstName: string, lastName?: string) { if (lastName) return firstName + " " + lastName; else return firstName; }
|
默认参数
1 2 3
| function buildName(firstName: string, lastName = "Smith") { return firstName + " " + lastName; }
|
剩余参数
1 2 3 4
| function buildName(firstName: string, ...restOfName: string[]) { return firstName + " " + restOfName.join(" "); } let buildNameFun: (fname: string, ...rest: string[]) => string = buildName;
|
函数类型
1 2 3 4
|
let myAdd:(x:number, y:number) => number = (x: number, y: number): number { return x + y; };
|
注意:不要混淆了 TypeScript 中的 => 和 ES6 中的 =>,在 TypeScript 的类型定义中,=> 用来表示函数的定义,=> 的左边是输入类型,需要用括号括起来,右边是输出类型
上例还可以写做:
1 2 3
| type AddFunc = (x:number, y:number) => number
let myAdd:AddFunc = (x: number, y: number): number { return x + y; };
|
或者:
1 2 3 4 5
| interface AddFunc { (x:number, y:number):number }
let myAdd:AddFunc = (x: number, y: number): number { return x + y; };
|
this
略。。。
重载
略。。。
字面量类型
类
js 基础复习
什么是构造函数
在 JavaScript 中,用 new 关键字来调用的函数,称为构造函数。构造函数首字母一般大写。
es6 的 class 类本质上是对构造函数的封装,示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Greeter { constructor(message) { this.greeting = message; } greet() { return "Hello, " + this.greeting; } } let greeter = new Greeter("world"); console.log(greeter.greet());
function Greeter(message) { this.greeting = message; } Greeter.prototype.greet = function () { return "Hello, " + this.greeting; };
let greeter = new Greeter("world"); console.log(greeter.greet());
|
js 中的 this 指向
- 函数中的 this:window
- 方法中的 this:调用他的对象
- 构造函数中的 this:通过构造函数创建的实例
- 事件处理函数中的 this:触发事件的对象
- 定时器执行的 function 中的 this:window
pubic、private、protected
B 继承 A,A 是基类,B 是派生类,基类通常被称为超类,派生类通常被称作子类,子类如果有构造函数,它必须要调用super()
。
- public:类成员(属性和方法)默认是 publc
- private:当成员被标记成 private 时,它就不能在声明它的类的外部访问
- protected:protected 修饰符与 private 修饰符的行为很相似,但有一点不同, protected 成员在派生类中仍然可以访问
readonly 修饰符
可以使用 readonly 关键字将属性设置为只读。 只读属性必须在声明时或构造函数里被初始化。
参数属性
存取器
首先,存取器要求你将编译器设置为输出 ECMAScript 5 或更高。 不支持降级到 ECMAScript 3。 其次,只带有 get 不带有 set 的存取器自动被推断为 readonly 。
静态属性
静态属性存在于类本身上面而不是类的实例上,关键字 static
定义静态属性,实例属性使用 this 访问,静态属性通过类名调用。
抽象类
关键字 abstract
定义抽象类和在抽象类内部定义抽象方法。
示例:
1 2 3 4 5 6
| abstract class Animal { abstract makeSound(): void; move(): void { console.log("roaming the earth..."); } }
|
高级技巧
构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Greeter { static standardGreeting = "Hello, there"; greet() { return Greeter.standardGreeting; } } let greeter1: Greeter = new Greeter(); console.log(greeter1.greet());
let greeterMaker: typeof Greeter = Greeter; greeterMaker.standardGreeting = "Hey there!";
let greeter2: Greeter = new greeterMaker(); console.log(greeter2.greet());
|
把类当做接口使用