TypeScript相比JavaScript的优势
- ts是js的超集,存在类型的脚本语言
- 强大的类型系统,拥有静态类型检查能力
- 新增类型注解和类型推断
- 拥有丰富的class扩展功能
- 编译期进行类型检查
- 开发环境能提供丰富的信息
- 大部分检查有语言自身完成
基础类型和对象类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| const count: number = 123; const studentName: string = "neo";
const numbers: number[] = [1, 2, 3];
type Student = { name: string, age: number }
const student: Student = { name: "neo", age: 188 }
const getTotal: () => number = () => { return 123; }
|
类型注解和类型推断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
type myType = string | number
const one: myType = 1 const two: myType = '2'
let three = 3
function add(first, second) { return first + second; }
const total = add(1, 2);
|
函数类型需要对返回值进行约束
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function add(first: number, second: number) { return first + second + ''; }
const total = add(1, 2);
function add(first: number, second: number): number { return first + second + ''; }
const total = add(1, 2);
const hello = ({ name, age }: { name: string; age: number }): string => { return `hello ${name}, ${age} years old`; }
const res = hello({ name: 'xiuji', age: 18 });
|
数组与元组
使用注解规定对应变量/常量的数据类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const strArr: string[] = ['a', 'b', 'c'] const numArr: number[] = [1, 2, 3] const undefinedArr: undefined[] = [undefined, undefined]
const objArr: { name: string, age: number }[] = [ { name: 'neo', age: 18 }, ]
type User = { name: string, age: number } const objArr2: User[] = [{ name: 'neo', age: 18 }]
const tuple: [string, number, boolean] = ['a', 1, false]
const csvArr: [string, number][] = [['a', 1], ['b', 2], ['c', 3]]
|
interface接口
接口定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| interface Person { name: string; age: number; }
type Person1 = { name: string; }
const setPersonName = (person: Person, name: string) => { person.name = name; }
const getPersonName = (person: Person1) => { console.log(person.name); }
const person = { name: 'neo' }
setPersonName(person, 'neo1'); getPersonName(person);
|
接口中定义了对应类型,使用接口的地方定义的变量或字面量必须包含接口中所有类型
接口校验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| interface Person { name: string; age?: number; }
const setPersonName = (person: Person, name: string): void => { person.name = name; }
const getPersonName = (person: Person): void => { console.log(person.name); }
const person = { name: 'neo', sex: 'male', }
getPersonName({ name: 'neo', sex: 'male', }); 对象字面量只能指定已知属性,并且“sex”不在类型“Person”中 getPersonName(person);
setPersonName(person, 'neo1');
|
使用字面量形式传参,ts会对字面量进行强校验。使用变量形式传参,ts会对变量进行弱校验。
1 2 3 4 5 6 7 8 9 10
| interface Person { name: string; age?: number; [propName: string]: any; }
getPersonName({ name: 'neo', sex: 'male', });
|
接口中还可以定义方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| interface Person { name:string; age?:number; [propName: string]: any; say(): string; }
const person = { name: 'neo', sex: 'male', say() { return 'hello world'; } }
|
implements和extends关键字
1 2 3 4 5 6 7 8 9 10 11 12 13
| class User implements Person { name = 'terminal'; say() { return 'im bak'; } }
interface Son extends Person { cry(): boolean; }
|
type 和 interface 的区别
type
关键字是声明类型别名的关键字。它的语法如下:
- type:声明类型别名的关键字
- AliasName:类型别名的名称
- Type:类型别名关联的具体类型
通过关键字 interface
可以定义一个接口类型。它能合并众多类型声明至一个类型声明。
接口声明只存在于编译阶段,在编译后的JS代码中不包含任何接口代码
语法如下:
1 2 3 4 5
| interface InterfaceName { TypeMember; TypeMember; ... }
|
- interface:定义接口的关键字
- InterfaceName:接口名,首字母需要大写
- TypeMember:接口的类型成员
不同点
- type 在声明类型别名之后实际上是一个赋值操作,它需要将别名与类型关联起来。也就是说类型别名不会创建出一种新的类型,它只是给已有类型命名并直接进行引用。
interface
是定义了一个接口类型。
- type 能够表示非对象类型, 而
interface
则只能表示对象类型。
interface
可以继承其他的接口、类等对象类型, type
不支持继承。
类型别名可以借助交叉类型来实现继承的效果。而这种方法也只适用于表示对象类型的类型别名,对于非对象类型是无法使用的。
1 2 3 4 5 6 7 8
| type Football = { name: string }
type Basketball = Football & { ball: number }
function foo(basketball: Basketball) { const name = basketball.name const radius = basketball.radius }
|
interface
接口名总是会直接显示在编译器的诊断信息和代码编辑器的智能提示中,而 type 的名字只在特定情况下才会显示出来——只有当类型别名表示数组类型、元组类型以及类或者接口的泛型实例类型时才展示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| type NumberOrBigint = number | bigint;
interface ItemNum { count: number; }
function f(itemNum: ItemNum, value: NumberOrBigint) { const ball: number = value; const coffee: number = itemNum; }
|
类的定义与继承
定义
1 2 3 4 5 6 7 8 9 10 11 12
| class Animal { name: string; constructor(name: string) { this.name = name; } run(): string { return `${this.name} is running` } }
const snake = new Animal('lily'); console.log(snake.run());
|
继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Dog extends Animal { bark(): string { return `${this.name} is barking` } run(): string { return 'dog ' + super.run() } }
const dog = new Dog('dog'); console.log(dog.run());
|
类中的访问类型和构造器
类中有public、private、protected修饰符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class Father { public name: string; private age: number; protected occupation: string; constructor(name: string, age: number, occupation: string) { this.name = name; this.age = age; this.occupation = occupation; }; say(): void { console.log(this.name); console.log(this.age); } }
const father = new Father("xiuji's daddy", 998, 'coder') console.log(father.name) console.log(father.age) console.log(father.occupation)
class Son extends Father { constructor(public age: number) { super("xiuji's daddy", 988, 'coder') } wishToBe(): void { console.log(this.occupation); } }
const son = new Son() console.log(son.wishToBe())
|
constructor简化写法:不定义属性名,通过constructor(public 属性名: 类型)
的形式定义
1 2 3 4 5 6 7 8 9
| class Father { public name: string; constructor(name: string) { this.name = name; } constructor(public name: string) { } }
|
**ps:**子类继承父类,即使父类中没有属性,子类中也需要调用super
1 2 3 4 5 6 7 8 9
| class Father { }
class Son extends Father { constructor(public age: number) { } }
|
静态属性、Setter和Getter
实现单例模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Demo { private static instance: Demo; private constructor(public name: string) {} static getInstance(name: string) { if (!this.instance) { this.instance = new Demo(name) } return this.instance } }
const demo1 = Demo.getInstance('snake') const demo2 = Demo.getInstance('snake1') console.log(demo1.name); console.log(demo2.name);
|
Setter和Getter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class Demo { constructor(private _name: string) { } get name() { const relaName = this._name + new Date().getTime() return relaName } set name(name: string) { const relaName = name.split(' ')[0] this._name = relaName } } const demo = new Demo('snake') console.log(demo.name); demo.name = 'snakeA xiuji' console.log(demo.name);
|