安装编译工具
npm install typescript -g
基本命令
npx tsc --init
: 初始化配置文件 tsconfig.jsonnpx tsc -w
: 监听文件变化,实时编译
基本类型
类型
- boolean: 布尔值
- number: 数字,可以是整数、浮点数、各种进制
- string: 字符串
- Array<number>: 数组,尖括号内为数组元素的类型
- [string, number]: 元组,有限长度的数组,可以指定每一个元素的类型
- enum: 枚举,默认从0开始
- unknown: 未知类型,可以是任意值,但依然会被类型检测
- any: 任意类型,可以是任意值,编译期间不做类型检测
- void: 空值,一般用作无返回的函数
- null: null值,一般不使用
- undefined: undefined值,一般用作函数默认参数的占位符
- never: never类型,有2种情况:无法执行到最后的函数(异常,死循环),返回never的函数,常用于类型收窄(全面类型检查)
- object: 对象类型
类型断言
as关键词: someValue(某变量) as string(某类型),当你比编译器了解的更多的时候,可以用类型断言来辅助编译器
类型大小写的问题
在ts中,都使用小写(number, string, boolean, symbol, object),大写是js中的原语类型(Number, String, Boolean, Symbol, Object),在ts中不应该被使用
接口
接口类型
- 对象:指定对象属性的类型
- 函数:指定函数参数和返回值的类型
- 索引:指定索引的类型,比如number,string。如果是string,则索引既可以是string,也可以是number。如果是number,则索引只能是number
- 类:指定类的构造函数、实例属性和方法,定义一个类必须同时定义2个接口,一个是构造函数的,一个是实例属性和方法的
- 混合:指的是即是函数也是对象的一种类型,可以像函数一样调用,可有自己的属性和方法
属性类型
- 可选属性:用问号,例:color?: string
- 只读属性:用readonly关键词,例:readonly color: string
属性检查
编译器会对实现接口的函数调用,进行属性检查,如果传入参数直接是对象本身,会对接口定义之外的属性报错,有两种办法解决该问题
- 使用as关键词做类型断言
- 使用变量去承载该对象,传入变量到参数
注:尽可能地不要使用接口定义之外的属性,实在不行,就用as关键词
继承
- 接口继承接口:相当于直接copy所有的属性,可以同时继承多个
- 接口继承类:同上copy所有属性,包括private和protected,但该接口的实现类必须是该类本身或者是该类的子类
函数
声明式函数
function myAdd (x: number, y: number): number {
return x + y
}
赋值式函数
let myAdd: (x: number, y:number) => number = function(x: number, y: number): number {
return x + y
}
类型推断
针对赋值式函数,可以省去一边的类型定义,因为编译器会根据另一边推断出具体类型
let myAdd = function(x: number, y: number): number {
return x + y
}
let myAdd2: (x: number, y:number) => number = function(x, y) {
return x + y
}
参数类型
- 可选参数:用问号,color?: string
- 默认参数:用等号,color = '#000000'
- 默认参数的字面量会让编译器推断出具体类型,所以无需再加上类型定义
- 默认参数也是可选参数
- 剩余参数:用...,(x: number, ...restOfNumber: Array<number>)
this参数
函数第一个参数如果是this,则是对this的类型约束,没有特定需要,一般不去设置this参数
重载
定义多个同名函数,最后一个函数为具体实现,前面的函数为参数声明
注:ts的函数重载只是为了类型检测,与其他语言可能会有差异
字面量类型
- 字符串
- 数字
- 布尔值
并集和交集类型
- 并集:let pet = Fish | Bird
- 交集:let dom = Dom & Event
类
继承
class Animal {
move(x: number = 0) {
console.log(`Animal moved ${x}m.`);
}
}
class Dog extends Animal {
bark() {
console.log("Woof! Woof!");
}
}
const dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();
修饰符
- public: 都可使用
- private:只有本类可以使用,子类和外部实例不允许使用,es6的私有属性也支持,如:#name: string
- protected: 只有父类和子类的函数可以使用,外部实例不允许使用
- readonly:只读属性,只有定义和构造函数可以给这些属性赋值
参数属性
构造函数的参数如果带有任意修饰符,则该属性默认属于实例属性
访问器
get和set模型
静态属性
属于类本身的属性,只能通过类名访问
接口类
不可被实例化,只能被继承
构造函数
用new关键字创建实例的时候,自动执行的初始化函数
枚举
数字型枚举
初始为数字的枚举类型,默认从0开始,可以指定为任意数字,如果未指定,则沿用上一个常量+1
字符串型枚举
不再拥有自动加一的特性,必须指定每一个枚举值
混合类型
同时拥有字符串和数字的混合类型,不建议使用
计算成员和常量成员
以下情况符合其一就是常量成员
- 第一个成员没有初始值,默认是0
- 没有初始值,且前一个成员为数字型常量
- 字面量和部分数学符号组成的表达式,如:-1, '123'.length, 1 << 1等
联合枚举和枚举成员类型
- 联合枚举:枚举类型拥有有限个成员,这些成员组成了类型的并集,在一些条件判断的时候,编译器可以去识别这些类型,如果条件为恒真或者恒假,则会提示错误,例:
enum E {
Foo,
Bar,
}
function f(x: E) {
if (x !== E.Foo || x !== E.Bar) {
// This condition will always return 'true' since the types 'E.Foo' and 'E.Bar' have no overlap.
//
}
}
- 枚举成员类型:针对枚举类型的常量成员,也是一种独立的类型,例:
enum ShapeKind {
Circle,
Square,
}
interface Circle {
kind: ShapeKind.Circle;
radius: number;
}
interface Square {
kind: ShapeKind.Square;
sideLength: number;
}
let c: Circle = {
kind: ShapeKind.Square,
// Type 'ShapeKind.Square' is not assignable to type 'ShapeKind.Circle'.
radius: 100,
};
枚举运行时
在运行时,枚举类型是真实存在的,可以打印出对应的值
枚举编译时
运行时,枚举类型虽然存在,但对应的key的字符串却可能跟你预期的不一样,编译时可以用 keyof typeof
关键词来获取key的联合类型,例:
enum LogLevel {
ERROR,
WARN,
INFO,
DEBUG,
}
/**
* This is equivalent to:
* type LogLevelStrings = 'ERROR' | 'WARN' | 'INFO' | 'DEBUG';
*/
type LogLevelStrings = keyof typeof LogLevel;
反向映射
数字型枚举类型,可以根据数字获取到key的字符串,例:
enum Enum {
A,
}
let a = Enum.A;
let nameOfA = Enum[a]; // "A"
常量枚举
在枚举关键词之前使用 const
关键词,可以避免编译产生额外的代码和反向映射,项目中推荐使用
环境枚举
用来定义已存在的枚举类型,不会编译成代码,在枚举类型前使用 declare
关键词,例:
declare enum Enum {
A = 1,
B,
C = 2,
}
泛型
为了提高代码复用率,泛型可以允许指定类型参数,来创建逻辑相同的代码片段(类型,类,函数),例:
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("myString");
泛型类型变量
上面的示例,arg的参数类型是不确定的,如果要使用数组类型的length属性,需要使用泛型数组类型,例:
function identity<T>(arg: Array<T>): Array<T> {
console.log(arg.length)
return arg;
}
泛型类型
上面的示例,要利用泛型函数来创建一个新的函数,可以用以下代码:
let myIdentify: <T>(arg: T) => T = identify
这里T只是一个标识符,也可以用其他任意字符替代
我们也可以用调用签名的方式去写(对象字面量类型):
let myIdentify: {<T>(arg: T): T} = identify
初看之下可能比较复杂,但实际上就是一个对象的key,value的键值对,key表示输入,value表示输出
因此衍生出使用泛型接口来重写上面的代码,将调用签名抽离成一个函数类型的接口:
interface GenericIdentityFn {
<T>(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn = identity;
然后可以将泛型参数转移到整个接口上,这样所有成员函数都可以使用这个泛型参数:
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;
泛型接口的使用看具体业务情况
泛型类
就是在类的基础上扩展了泛型参数,唯一需要注意的是,静态成员无法使用泛型参数
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
泛型约束
泛型参数一般是类似any的存在,如果需要使用它的一些属性,比如length,则需要额外定义,可以使用Array,或者也可以使用继承的方式,创建一个接口,指定属性来约束泛型参数,例:
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}
注:这样一来,函数传参必然是一个包含length属性的对象,就不能是任意值了
泛型中使用类
当使用泛型在ts中创建工厂时,则有必要引用类的构造函数,例:
function create<T>(c: { new (): T }): T {
return new c();
}
以下是具体示例:
class BeeKeeper {
hasMask: boolean;
}
class ZooKeeper {
nametag: string;
}
class Animal {
numLegs: number;
}
class Bee extends Animal {
keeper: BeeKeeper;
}
class Lion extends Animal {
keeper: ZooKeeper;
}
function createInstance<A extends Animal>(c: new () => A): A {
return new c();
}
createInstance(Lion).keeper.nametag;
createInstance(Bee).keeper.hasMask;
参考
www.typescriptlang.org/docs/handbo…
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!