1、安装TypeScript
1. 安装TypeScript
npm install -g typescript
2. 使用 tsc 全局命令
// 查看 tsc 版本
tsc -v
// 编译 ts 文件
tsc fileName.ts
3. 使用ts-node
npm install -g ts-node
ts-node fileName.ts
2、基本类型
2.1 原始数据类型
JavaScript 的原始数据类型:
- boolean 、 number 、 string 、 symbol 、 bigint
- undefined 、 null
let isDone: boolean = false
let age: number = 10
let binaryNumber: number = 0b1111
let name: string = 'lionkliu'
let message: string = `Hello, ${name}, age is ${age}`
// 还有undefined 和 null,不常用
let u: undefined = undefined
let n: null = null
// undefined 和 null 是所有类型的子类型。
// TS 的非严格模式下,可赋值给其他类型。
let num: number = undefined
如果指定了 --strictNullChecks 标记,null 和 undefined 只能赋值给 void 和它们各自,不然会报错。
2.2 void、never、any、unkown、null、undefined
void
类型变量只能为它赋值undefined
和null
,当一个函数没有返回值时,通常会见到其返回值类型是 void
let unusable: void = undefined;
function warnUser(): void {
console.log("This is my warning message");
}
never
类型是那些总是会抛出异常 或 根本就不会有返回值的函数
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
// 推断的返回值类型为never
function fail() {
return error("Something failed");
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
while (true) {
}
}
never 类型是任何类型的子类型,也可以赋值给任何类型。
没有类型是 never 的子类型,没有类型可以赋值给 never 类型(除了 never 本身之外)
any
类型,回到了JavaScript
let notSure: any = 4
notSure = 'maybe it is a string'
notSure = 'boolean'
// 在任意值上访问任何属性都是允许的:
notSure.myName
// 也允许调用任何方法:
notSure.getName()
在许多场景下,这太宽松了。使用
any
类型,可以很容易地编写类型正确但在运行时有问题的代码。如果我们使用any
类型,就无法使用 TypeScript 提供的大量的保护机制。为了解决any
带来的问题,TypeScript 3.0 引入了unknown
类型。
- unkown 当我们在写应用的时候可能会需要描述一个我们还不知道其类型的变量。
let value: unknown;
value = true; // OK
value = 42; // OK
value = "Hello World"; // OK
value = []; // OK
value = {}; // OK
value = Math.random; // OK
value = null; // OK
value = undefined; // OK
value = new TypeError(); // OK
value = Symbol("type"); // OK
所有类型都可以赋值给
any
,所有类型也都可以赋值给unknown
。这使得unknown
成为 TypeScript 类型系统的另一种顶级类型(另一种是any
)
let value: unknown;
let value1: unknown = value; // OK
let value2: any = value; // OK
let value3: boolean = value; // Error
let value4: number = value; // Error
let value5: string = value; // Error
let value6: object = value; // Error
let value7: any[] = value; // Error
let value8: Function = value; // Error
unknown
类型只能被赋值给any
类型和unknown
类型本身。直观地说,只有能够保存任意类型值的容器才能保存unknown
类型的值。
- 默认情况下
null
和undefined
是所有类型的子类型。 就是说你可以把null
和undefined
赋值给number
类型的变量。
let u: undefined = undefined;
let n: null = null;
然而,如果你指定了
--strictNullChecks
标记,null
和undefined
只能赋值给void
和它们各自的类型。
2.3 数组 Array
let list: number[] = [1, 2, 3];
// ES5:var list = [1,2,3];
let list: Array<number> = [1, 2, 3]; // Array<number>泛型语法
// ES5:var list = [1,2,3];
2.4 元组 Tuple
元组可用于定义具有有限数量的未命名属性的类型。每个属性都有一个关联的类型。使用元组时,必须提供每个属性的值。
// Declare a tuple type
type StringNumberPair = [string, number];
let x: [string, number];
x = ['hello', 10]; // OK
x = [10, 'hello']; // Error
2.5 枚举 enum
// 默认情况下,从 0 开始为元素编号。 你也可以手动的指定成员的数
enum Direction {
Up, // 相当于 = 0
Down,
Left,
Right,
}
console.log(Direction.Up) //0
// 反向映射
console.log(Direction[0])
// 如果枚举第一个元素赋有初始值,就会从初始值开始递增
enum Direction {
Up = 6,
Down,
Left,
Right
}
// 字符串枚举
enum Direction {
Up = 'UP',
Down = 'DOWN',
Left = 'LEFT',
Right = 'RIGHT',
}
const value = 'UP'
if (value === Direction.Up) {
console.log('go up!')
}
2.6 object、 Object 和 {} 类型
- object 类型用于表示所有的非原始类型,即我们不能把 number、string、boolean、symbol等 原始类型赋值给 object。在严格模式下,null 和 undefined 类型也不能赋给 object。
let object: object;
object = 1; // 报错
object = "a"; // 报错
object = true; // 报错
object = null; // 报错
object = undefined; // 报错
object = {}; // 编译正确
- 大 Object 代表所有拥有 toString、hasOwnProperty 方法的类型 所以所有原始类型、非原始类型都可以赋给 Object (严格模式下 null 和 undefined 不可以)
let bigObject: Object;
object = 1; // 编译正确
object = "a"; // 编译正确
object = true; // 编译正确
object = null; // 报错
ObjectCase = undefined; // 报错
ObjectCase = {}; // ok
- {} 空对象类型和大 Object 一样 也是表示原始类型和非原始类型的集合
3、高级类型
3.1 类型推导
TypeScript里,在有些没有明确指出类型的地方,类型推论会帮助提供类型
let x = 3; // 变量x的类型被推断为数字。
// 这种推断发生在初始化变量和成员,设置默认参数值和决定函数返回值时。
3.2 联合类型 |
联合类型表示一个值可以是几种类型之一,联合类型通常与 null
或 undefined
一起使用:
const sayHello = (name: string | undefined) => {
};
这里 name
的类型是 string | undefined
意味着可以将 string
或 undefined
的值传递给sayHello
函数。
sayHello("Semlinker");
sayHello(undefined);
3.3 交叉类型 &
交叉类型是将多个类型合并为一个类型
interface IPerson {
id: string;
age: number;
}
interface IWorker {
companyId: string;
}
type IStaff = IPerson & IWorker;
const staff: IStaff = {
id: 'E1006',
age: 33,
companyId: 'EFT'
};
3.4 类型断言 as
/<Type>
// 这里我们可以用 as 关键字,告诉typescript 编译器我们要指定的类型
function getLength(input: string | number): number {
const str = input as string
if (str.length) {
return str.length
} else {
const number = input as number
return number.toString().length
}
}
// 尖括号语法,类似与Java强转
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
3.5 类型守卫
类型保护是可执行运行时检查的一种表达式,用于确保该类型在一定的范围内,或用于获取变量类型信息,通常使用在条件块语句中。类型守卫是返回布尔值的常规函数,接受一个类型并告诉TypeScript是否可以缩小到更具体的类型。类型守卫具有唯一的属性,可以确保测试的值返回的是布尔值类型。
in
关键字
in
关键字 类型守卫检查对象是否具有特定的属性,并使用该属性区分不同的类型。它通常返回一个布尔值,表示该属性是否存在于该对象中。
语法:'propertyName' in objectName
interface Admin {
name: string;
privileges: string[];
}
interface Employee {
name: string;
startDate: Date;
}
type UnknownEmployee = Employee | Admin;
function printEmployeeInformation(emp: UnknownEmployee) {
console.log("Name: " + emp.name);
if ("privileges" in emp) {
console.log("Privileges: " + emp.privileges);
}
if ("startDate" in emp) {
console.log("Start Date: " + emp.startDate);
}
}
typeof
关键字
typeof
关键字 用来确定变量的类型
function padLeft(value: string, padding: string | number) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
instanceof
关键字
instanceof
关键字 :可用于检查一个值是否是给定构造函数或类的实例。有了这个类型守卫,我们可以判断一个对象或值是否派生自一个类,这对于确定实例类型的类型很有用。
interface Padder {
getPaddingString(): string;
}
class SpaceRepeatingPadder implements Padder {
constructor(private numSpaces: number) {}
getPaddingString() {
return Array(this.numSpaces + 1).join(" ");
}
}
class StringPadder implements Padder {
constructor(private value: string) {}
getPaddingString() {
return this.value;
}
}
let padder: Padder = new SpaceRepeatingPadder(6);
if (padder instanceof SpaceRepeatingPadder) {
// padder的类型收窄为 'SpaceRepeatingPadder'
}
自定义类型保护的类型谓词
function isNumber(x: any): x is number {
return typeof x === "number";
}
function isString(x: any): x is string {
return typeof x === "string";
}
3.6 类型别名
类型别名用来给一个类型起个新名字。
type Message = string | string[];
let greet = (message: Message) => {
};
4、接口 interface
4.1 Typescript 中的 interface 是什么
在面向对象语言中,接口是对行为的抽象,而具体如何行动需要由类(classes)去实现(implement)。而在TypeScript 中的接口是一个非常灵活的概念,除了可用于[对类的一部分行为进行抽象]以外,也常用于对「对象的形状(Shape)」进行描述。比喻:
鸭式辨型法:像鸭子一样走路并且嘎嘎叫的就叫鸭子
,即具有鸭子特征的认为它就是鸭子,也就是通过制定规则来判定对象是否实现这个接口。
4.2 interface 定义
赋值的时候,变量的形状必须和接口的形状保持一致
// 我们定义了一个接口 Person
interface Person {
name: string;
age: number;
}
let liu: Person ={
name: 'liu666',
age: 20
}
4.3 可选属性 ?
//可选属性:
interface Person2 {
name: string;
age?: number;
}
let liu2: Person2 = {
name: 'liu666'
}
let liu3: Person2 = {
name: 'liu888'
age:20
}
// age可选
4.4 只读属性 readonly
//只读属性
interface Person3 {
readonly id: number;
name: string;
age?: number;
}
liu.id = 9527 // error
5、函数 function
function add(x: number, y: number): number {
return x + y
}
// 可选参数
function add(x: number, y: number, z?: number): number {
if (typeof z === 'number') {
return x + y + z
} else {
return x + y
}
}
// 函数本身的类型
let myAdd: (x:number, y:number) => number =
function(x: number, y: number): number { return x + y; };
6、类 class
6.1 类的定义 class
及继承 extends
class Animal {
name: string;
// 构造函数
constructor(name: string) {
this.name = name
}
run() {
return `${this.name} is running`
}
}
const snake = new Animal('lily')
// 继承的特性
class Dog extends Animal {
bark() {
return `${this.name} is barking`
}
}
const xiaobao = new Dog('xiaobao')
console.log(xiaobao.run())
console.log(xiaobao.bark())
// 这里我们重写构造函数,注意在子类的构造函数中,必须使用 super 调用父类的方法,要不就会报错。
class Cat extends Animal {
constructor(name) {
super(name)
console.log(this.name)
}
run() {
return 'Meow, ' + super.run()
}
}
const maomao = new Cat('maomao')
console.log(maomao.run())
- public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的
- private 修饰的属性或方法是私有的,不能在声明它的类的外部访问
- protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的
6.2 抽象类 abstract
所谓抽象类,是指只能被继承,但不能被实例化的类。抽象类有以下两个特点:
- 抽象类不允许被实例化
- 抽象类中的抽象方法必须被子类实现
abstract class Animal {
constructor(name:string) {
this.name = name
}
public name: string
public abstract sayHi():void
}
class Dog extends Animal {
constructor(name:string) {
super(name)
}
public sayHi() {
console.log('wang')
}
}
6.3 类和接口
7、泛型 <T>
7.1 什么是泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。常见泛型变量代表的意思:
-
T(Type):表示一个 TypeScript 类型
-
K(Key):表示对象中的键类型;
-
V(Value):表示对象中的值类型;
-
E(Element):表示元素类型。
7.2 泛型约束
泛型约束的作用就是限制每个类型变量接受的类型数量。
在函数内部使用泛型变量的时候,由于事先不知道它是哪种类型,所以不能随意的操作它的属性或方法:
function getLength<T>(arg:T):T {
console.log(arg.length); // 报错,不能调用 length 属性
}
因为泛型 T 不一定包含属性 length,那么我想 getLength 这个函数只允许传入包含 length 属性的变量,该怎么做呢?这时,我们可以使用extends
关键字来对泛型进行约束
interface Lengthwise {
length: number;
}
function getLength<T extends Lengthwise>(arg:T):T {
console.log(arg.length);
return arg;
}
7.3 泛型接口
在定义接口的时候指定泛型
interface KeyValue<T,U> {
key: T;
value: U;
}
const person1:KeyValue<string,number> = {
key: '树哥',
value: 18
}
const person2:KeyValue<number,string> = {
key: 20,
value: '张麻子'
}
7.4 泛型类
class Test<T> {
value: T;
add: (x: T, y: T) => T;
}
let myTest = new Test<number>();
myTest.value = 0;
myTest.add = function (x, y) {
return x + y;
};
8、类型声明
参考:
https://juejin.cn/post/6844904182843965453
评论区